Merge pull request #10375 from supabase/docs/delete-old-directory

Delete old docs directory
This commit is contained in:
dng authored and GitHub committed 2022-11-18 09:11:12 -08:00
commit 0caec908cf
786 files changed
+491 -77331

No files matched your search

+1 -1
View File
@@ -28,7 +28,7 @@
"gen:supabase-js:v1": "npm-run-all gen:supabase-js:v1:ref",
"gen:supabase-js:v1:ref": "ts-node ./generator/index.ts gen --type legacy --input ../../spec/supabase_js_v1.yml --output ./docs/reference/javascript/v1/generated",
"gen:supabase-js:v2": "npm-run-all gen:supabase-js:v2:ref",
"gen:supabase-js:v2:ref": "ts-node ./generator/index.ts gen --type legacy --input ../../spec/supabase_js_v2_temp.yml --output ./docs/reference/javascript/generated"
"gen:supabase-js:v2:ref": "ts-node ./generator/index.ts gen --type legacy --input ../../spec/supabase_js_v2.yml --output ./docs/reference/javascript/generated"
},
"dependencies": {
"@algolia/autocomplete-js": "^1.7.2",
+1
View File
@@ -89,3 +89,4 @@ Supabase is just Postgres, which makes it compatible with a large number of tool
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
-22
View File
@@ -1,22 +0,0 @@
# Dependencies
/node_modules
# Production
/build
# Generated files
.docusaurus
.cache-loader
# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
**/*/generated
-20
View File
@@ -1,20 +0,0 @@
# Dependencies
/node_modules
# Production
/build
# Generated files
.docusaurus
.cache-loader
# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
-105
View File
@@ -1,105 +0,0 @@
# Developing Supabase Docs
1. [Development setup](#development-setup)
- [Install dependencies](#install-dependencies)
- [Fork the repository](#fork-the-repository)
2. [Build Supabase](#build-supabase)
- [Run the docs locally](#run-the-docs-locally)
- [Editing files](#editing-files)
3. [Create a pull request](#create-a-pull-request)
- [Monorepo](#monorepo)
- [Community channels](#community-channels)
## Development setup
Thanks for your interest in Supabase and for wanting to contribute! Before you begin, read the
[code of conduct](https://github.com/supabase/.github/blob/main/CODE_OF_CONDUCT.md) and check out the
[existing issues](https://github.com/supabase/supabase/issues).
This document describes how to set up your development environment to build and test Supabase.
### Install dependencies
You need to install and configure the following dependencies on your machine to build Supabase:
- [Git](http://git-scm.com/)
- [Node.js v16.x (LTS)](http://nodejs.org)
- [npm](https://www.npmjs.com/) version 7+ or [Yarn](https://yarnpkg.com/)
### Fork the repository
To contribute code to Supabase, you must fork the [Supabase Repository](https://github.com/supabase/supabase).
## Build Supabase
1. Clone your GitHub forked repository:
```sh
git clone https://github.com/<github_username>/supabase.git
```
1. Go to the Supabase directory:
```sh
cd supabase
```
### Run the docs locally
1. Build the development server
npm
```sh
npm run build
```
or with yarn
```sh
yarn build
```
1. Start the development server
npm
```sh
npm run start
```
or with yarn
```sh
yarn start
```
1. Access the local server in your web browser at http://localhost:3010/docs.
---
### Editing files
Our docs site are comprised of guides, tutorials, quickstarts, and reference docs. Note that the [reference docs](https://supabase.com/docs/reference) are generated from spec files.
If you go to any page in the [Supabase docs](https://supabase.com/docs), you'll see an **Edit this page** link at the bottom. This link indicates which file you need to edit.
For example, the [NextJS Quickstart](https://supabase.com/docs/guides/with-nextjs) is a markdown file you can edit directly. However, this [signUp() reference doc](https://supabase.com/docs/reference/javascript/auth-signup) is generated from a [spec file](https://github.com/supabase/supabase/edit/master/spec/supabase_js_v1_legacy.yml).
## Create a pull request
After making your changes, open a pull request (PR). Once you submit your pull request, others from the Supabase team/community will review it with you.
Did you have an issue, like a merge conflict, or don't know how to open a pull request? Check out [GitHub's pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests) tutorial on how to resolve merge conflicts and other issues. Once your PR has been merged, you will be proudly listed as a contributor in the [contributor chart](https://github.com/supabase/supabase/graphs/contributors).
---
## Monorepo
We are in the process of migrating this repository to monorepo, using Turborepo.
This app is currently not in that workflow, but if you want to contribute to any of the other apps, please refer to [the developers readme](https://github.com/supabase/supabase/blob/master/DEVELOPERS.md).
---
## Community channels
Stuck somewhere? Have any questions? Join the [Discord Community Server](https://discord.supabase.com/) or the [Github Discussions](https://github.com/supabase/supabase/discussions). We are here to help!
-5
View File
@@ -1,5 +0,0 @@
# Reference Docs
## Deprecation notice
This directory is the old Supabase docs site. We have migrated to a new `docs` [(supabase/apps/docs)](https://github.com/supabase/supabase/tree/master/apps/docs) directory in November 2022 and will be removing this `reference` directory soon. Any contributions to docs going forward should be made in `docs` and not `reference`.
-37
View File
@@ -1,37 +0,0 @@
---
slug: /
sidebar_position: 1
sidebar_label: Management API
---
# Management API
The Management API allows you to manage your projects programmatically.
## Status
The Management API is in `beta`. It is usable in it's current state, but it's likely that there will be breaking changes.
## Authentication
All API requests require a Supabase Personal token to be included in the Authorization header: `Authorization Bearer <supabase_personal_token`.
To generate or manage your API token, visit your [account](https://app.supabase.com/account/tokens) page.
Your API tokens carry the same privileges as your user account, so be sure to keep it secret.
```bash
$ curl https://api.supabase.com/v1/projects \
-H "Authorization: Bearer sbp_bdd0••••••••••••••••••••••••••••••••4f23"
```
All API requests must be authenticated and made over HTTPS.
## Rate limits
The API is currently subject to our fair-use policy. In the future, are likely to introduce rate limits.
All resources created via the API are subject to the pricing detailed on our [Pricing](https://supabase.com/pricing) pages.
## Additional links
- [OpenAPI Docs](https://api.supabase.com/api/v1)
- [OpenAPI Spec](https://api.supabase.com/api/v1-json)
- Reporting bugs and issues: [github.com/supabase/supabase](https://github.com/supabase/supabase)
-12
View File
@@ -1,12 +0,0 @@
---
id: release-notes
---
# Release Notes
## v1.0.0 {#1.0.0}
Adds the following routes:
- `/v1/organizations`: Manage Supabase organizations
- `/v1/projects`: Manage Supabase projects
File diff suppressed because it is too large. Load diff
Whitespace-only changes.
Whitespace-only changes.
-1
View File
@@ -1 +0,0 @@
[]
Whitespace-only changes.
-29
View File
@@ -1,29 +0,0 @@
---
id: intro
slug: /
sidebar_position: 1
sidebar_label: Supabase CLI
hide_table_of_contents: true
---
# Supabase CLI
The Supabase CLI provides tools to develop your project locally and deploy to the Supabase Platform.
The CLI is still under development, but it contains all the functionality for working with your Supabase projects and the Supabase Platform.
- Run Supabase locally: [`supabase start`](https://supabase.com/docs/reference/cli/usage#supabase-start)
- Manage database migrations: [`supabase migration`](https://supabase.com/docs/reference/cli/usage#supabase-migration)
- CI/CD for releasing to production: [`supabase db push`](https://supabase.com/docs/reference/cli/usage#supabase-db-push)
- Manage your Supabase projects: [`supabase projects`](https://supabase.com/docs/reference/cli/usage#supabase-projects)
- Generate types directly from your database schema: [`supabase gen types`](https://supabase.com/docs/reference/cli/usage#supabase-gen)
- A [community-supported GitHub Action](https://github.com/lyqht/generate-supabase-db-types-github-action) to generate TypeScript types
- Shell autocomplete: [`supabase completion`](https://supabase.com/docs/reference/cli/usage#supabase-completion)
- A [community-supported Fig autocomplete spec](https://fig.io/manual/supabase) for macOS terminal
## Additional Links
- [Install the Supabase CLI](/docs/guides/cli)
- [Source code](https://github.com/supabase/cli)
- [Known bugs and issues](https://github.com/supabase/cli/issues)
- [Supabase CLI v1 and Management API Beta](https://supabase.com/blog/supabase-cli-v1-and-admin-api-beta)
- [The CLI team announcing CLI V1 and Management API Beta - Video](https://www.youtube.com/watch?v=OpPOaJI_Z28)
-7
View File
@@ -1,7 +0,0 @@
---
id: release-notes
---
# Release Notes
All release notes can be found in the [GitHub Releases page](https://github.com/supabase/cli/releases).
Whitespace-only changes.
Whitespace-only changes.
-1
View File
@@ -1 +0,0 @@
[]
-35
View File
@@ -1,35 +0,0 @@
---
id: config
slug: /config
title: Configuration
toc_max_heading_level: 3
---
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY -->
A `config.toml` file is generated after running `supabase init`.
This file is located in the `supabase` folder under `supabase/config.toml`.
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY -->
## General {#general}
### `project_id` {#project_id}
A string used to distinguish different Supabase projects on the same host. Defaults to the working directory name when running `supabase init`.
<ul>
<li>Required: <code>true</code></li>
<li>Default: <code>None</code></li>
</ul>
<br />
-22
View File
@@ -1,22 +0,0 @@
---
slug: /
sidebar_position: 1
sidebar_label: Auth Server
---
# Supabase Auth Server
The Supabase Auth Server (GoTrue) is a JSON Web Token (JWT)-based API for managing users and issuing access tokens.
GoTrue is an open-source API written in Golang, that acts as a self-standing API service for handling user registration and authentication for JAM projects. It's based on OAuth2 and JWT and handles user signup, authentication, and custom user data.
## Client libraries
- [JavaScript](https://github.com/supabase/gotrue-js)
- [Dart](https://github.com/supabase/gotrue-dart)
## Additional Links
- [Source Code](https://github.com/supabase/gotrue)
- [Known bugs and issues](https://github.com/supabase/gotrue/issues)
- [Auth Guides](https://supabase.com/docs/guides/auth)
-7
View File
@@ -1,7 +0,0 @@
---
id: release-notes
---
# Release Notes
All release notes can be found in the [GitHub Releases](https://github.com/supabase/gotrue/releases) page.
-18
View File
@@ -1,18 +0,0 @@
---
id: usage
slug: /usage
title: Usage
toc_max_heading_level: 3
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY IF THIS IS VERSION "next" -->
Documentation of the gotrue API.
<!-- AUTOGENERATED: DO NOT EDIT DIRECTLY IF THIS IS VERSION "next" -->
Whitespace-only changes.
Whitespace-only changes.
-1
View File
@@ -1 +0,0 @@
[]
Whitespace-only changes.
-58
View File
@@ -1,58 +0,0 @@
---
slug: /
sidebar_position: 1
sidebar_label: Realtime Server
---
# Supabase Realtime Server
Supabase Realtime is a server built with Elixir using the [Phoenix Framework](https://www.phoenixframework.org) that allows you to listen to changes in your PostgreSQL database via logical replication and then broadcast those changes via WebSockets.
There are two versions of this server: `Realtime` and `Realtime RLS`.
`Realtime` server works by:
1. listening to PostgreSQL's replication functionality (using PostgreSQL's logical decoding)
2. converting the byte stream into JSON
3. broadcasting to all connected clients over WebSockets
`Realtime RLS` server works by:
1. polling PostgreSQL's replication functionality (using PostgreSQL's logical decoding and [wal2json](https://github.com/eulerto/wal2json) output plugin)
2. passing database changes to a [Write Ahead Log Realtime Unified Security (WALRUS)](https://github.com/supabase/walrus) PostgresSQL function and receiving a list of authorized subscribers depending on Row Level Security (RLS) policies
3. converting the changes into JSON
4. broadcasting to authorized subscribers over WebSockets
### Why not just use PostgreSQL's `NOTIFY`?
A few reasons:
1. You don't have to set up triggers on every table.
2. `NOTIFY` has a payload limit of 8000 bytes and will fail for anything larger. The usual solution is to send an ID and then fetch the record, but that's heavy on the database.
3. `Realtime` server consumes two connections to the database, then you can connect many clients to this server. Easier on your database, and to scale up you just add additional `Realtime` servers.
### Benefits
1. The beauty of listening to the replication functionality is that you can make changes to your database from anywhere - your API, directly in the DB, via a console, etc. - and you will still receive the changes via WebSockets.
2. Decoupling. For example, if you want to send a new slack message every time someone makes a new purchase you might build that functionality directly into your API. This allows you to decouple your async functionality from your API.
3. This is built with Phoenix, an [extremely scalable Elixir framework](https://www.phoenixframework.org/blog/the-road-to-2-million-websocket-connections).
### Does this server guarantee delivery of every data change?
Not yet! Due to the following limitations:
1. Postgres database runs out of disk space due to Write-Ahead Logging (WAL) buildup, which can crash the database and prevent Realtime server from receiving and broadcasting changes. This can be mitigated in the Realtime RLS version of this server by setting the Postgres config `max_slot_wal_keep_size` to a reasonable size.
2. Realtime server can crash due to a larger replication lag than available memory, forcing the creation of a new replication slot and resetting replication to read from the latest WAL data.
3. When Realtime server falls too far behind for any reason, for example disconnecting from database as WAL continues to build up, then database can delete WAL segments the server still needs to read from, for example after reconnecting.
## Client libraries
- [JavaScript](https://github.com/supabase/realtime-js)
- [Dart](https://github.com/supabase/realtime-dart)
## Additional Links
- [Source Code](https://github.com/supabase/storage-api)
- [Known bugs and issues](https://github.com/supabase/storage-js/issues)
- [Storage Guides](https://supabase.com/docs/guides/storage)
- [OpenAPI Docs](https://supabase.github.io/storage-api/)
@@ -1,7 +0,0 @@
---
id: release-notes
---
# Release Notes
All release notes can be found in the [GitHub Releases](https://github.com/supabase/realtime/releases) page.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
-28
View File
@@ -1,28 +0,0 @@
---
slug: /
sidebar_position: 1
sidebar_label: Storage Server
---
# Supabase Storage Server
An S3 compatible object storage service that integrates with Postgres.
- Uses Postgres as it's datastore for storing metadata
- Authorization rules are written as Postgres Row Level Security policies
- Integrates with S3 as the storage backend (with more in the pipeline!)
- Extremely lightweight and performant
Read [this post](https://supabase.com/blog/supabase-storage) on why we decided to build a new object storage service.
## Client libraries
- [JavaScript](https://github.com/supabase/storage-js)
- [Dart](https://github.com/supabase/storage-dart)
## Additional Links
- [Source Code](https://github.com/supabase/storage-api)
- [Known bugs and issues](https://github.com/supabase/storage-js/issues)
- [Storage Guides](https://supabase.com/docs/guides/storage)
- [OpenAPI Docs](https://supabase.github.io/storage-api/)
@@ -1,7 +0,0 @@
---
id: release-notes
---
# Release Notes
All release notes can be found in the [GitHub Releases](https://github.com/supabase/storage-api/releases) page.
Whitespace-only changes.
Whitespace-only changes.
-1
View File
@@ -1 +0,0 @@
[]
Whitespace-only changes.
@@ -1,43 +0,0 @@
---
id: initializing
title: 'Initializing'
slug: initializing
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
## Flutter
For `supabase-flutter`, you will be using the static `initialize()` method on `Supabase` class.
### Flutter `initialize()`
```dart title="main.dart"
Future<void> main() async {
await Supabase.initialize(url: 'https://xyzcompany.supabase.co', anonKey: 'public-anon-key');
runApp(MyApp());
}
```
### Access `SupabaseClient` instance
Once you initialize Supabase in your `main()` method, you can access the `SupabaseClient` instance from anywhere in your app.
```dart
final supabase = Supabase.instance.client;
```
## Other Dart Projects
You can initialize a new Supabase client using the `SupabaseClient()` method.
The Supabase client is your entrypoint to the rest of the Supabase functionality
and is the easiest way to interact with everything we offer within the Supabase ecosystem.
### Dart `SupabaseClient()`
```dart
final supabase = SupabaseClient('https://xyzcompany.supabase.co', 'public-anon-key');
```
@@ -1,24 +0,0 @@
---
id: installing
title: 'Installing'
slug: installing
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
## Flutter
For Flutter project, you can use [supabase_flutter](https://pub.dev/packages/supabase_flutter) package.
```bash
flutter pub add supabase_flutter
```
## Other Dart projects
For non-Flutter projects using Dart, such as server-side Dart or Angular-Dart, you can use the [supabase](https://pub.dev/packages/supabase) package.
```bash
dart pub add supabase
```
-27
View File
@@ -1,27 +0,0 @@
---
id: intro
slug: /
sidebar_label: Supabase Flutter Library
---
# Supabase Flutter Library
This reference documents every object and method available in Supabase's isomorphic Flutter library, [`supabase-flutter`](https://pub.dev/packages/supabase_flutter).
You can use the `supabase-flutter` library to:
- interact with your Postgres database
- listen to database changes
- invoke Deno Edge Functions
- build login and user management functionality
- manage large files
## For non-Flutter projects
We also have [supabase-dart](https://github.com/supabase-community/supabase-dart) for non-Flutter Dart projects, such as server-side Dart or Angular-Dart.
supabase-dart shares most of the APIs with supabase-flutter without being dependent on Flutter so that you can use Supabase anywhere you can run Dart!
## Additional Links
- Source Code: [github.com/supabase/supabase-flutter](https://github.com/supabase/supabase-flutter)
- [Known bugs and issues](https://github.com/supabase/supabase-flutter/issues)
@@ -1,541 +0,0 @@
---
id: upgrade-guide
title: Upgrade to supabase-flutter v1
description: 'Learn how to upgrade to supabase-flutter v1.'
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
supabase-flutter focuses on improving the developer experience and making it easier to use. This guide will help you upgrade from supabase-flutter v0 to v1.
## Upgrade the client library
Update the package in your pubspec.yaml file.
```yaml
supabase_flutter: ^1.0.0
```
## Error handling
The way supabase-flutter throws error has changed in v1. In v0, errors were returned as a response. In v1, errors are thrown as exceptions. This makes it more intuitive as a Flutter developer to handle errors.
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
final res = await supabase.from('my_table').select().execute();
final error = res.error;
if(error != null) {
// handle error
}
final data = res.data;
```
</TabItem>
<TabItem value="1.x">
```dart
try {
final data = supabase.from('my_table').select();
} catch (error) {
// handle error
}
```
</TabItem>
</Tabs>
## Auth classes / methods
### Usage of `SupabaseAuthState` and `SupabaseAuthRequiredState` classes
In v0, `SupabaseAuthState` and `SupabaseAuthRequiredState` were required to handle automatic token refresh and to listen to auth state change. In v1, `SupabaseAuthState` and `SupabaseAuthRequiredState` are deprecated, and token refresh will happen automatically just by initializing Supabase. [`onAuthStateChange`](/docs/reference/dart/upgrade-guide#listening-to-auth-state-change) can be used to action on auth state change.
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
await Supabase.initialize(
url: 'SUPABASE_URL',
anonKey: 'SUPABASE_ANON_KEY',
);
...
class AuthState<T extends StatefulWidget> extends SupabaseAuthState<T> {
...
}
...
class AuthRequiredState<T extends StatefulWidget> extends SupabaseAuthState<T> {
...
}
```
</TabItem>
<TabItem value="1.x">
```dart
await Supabase.initialize(
url: 'SUPABASE_URL',
anonKey: 'SUPABASE_ANON_KEY',
);
```
</TabItem>
</Tabs>
### Listening to auth state change
`onAuthStateChange` now returns a `Stream`.
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
final authSubscription = supabase.auth.onAuthStateChange((event, session) {
// handle auth state change
});
// Unsubscribe when no longer needed
authSubscription.data?.unsubscribe();
```
</TabItem>
<TabItem value="1.x">
```dart
final authSubscription = supabase.auth.onAuthStateChange.listen((data) {
final AuthChangeEvent event = data.event;
final Session? session = data.session;
// handle auth state change
});
// Unsubscribe when no longer needed
authSubscription.cancel();
```
</TabItem>
</Tabs>
### Sign in with email and password
The signIn() method has been deprecated in favor of more explicit method signatures to help with type hinting. Previously it was difficult for developers to know what they were missing (e.g., a lot of developers didn't realize they could use passwordless magic links).
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
await supabase.auth.signIn(email: email, password: password);
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.auth.signInWithPassword(email: email, password: password);
```
</TabItem>
</Tabs>
### Sign in with magic link
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
await supabase.auth.signIn(email: email);
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.auth.signInWithOtp(email: email);
```
</TabItem>
</Tabs>
### Sign in with a third-party OAuth provider
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
await supabase.auth.signInWithProvider(
Provider.github,
options: AuthOptions(
redirectTo: kIsWeb
? null
: 'io.supabase.flutter://reset-callback/'),
);
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.auth.signInWithOAuth(
Provider.github,
redirectTo: kIsWeb ? null : 'io.supabase.flutter://reset-callback/',
);
```
</TabItem>
</Tabs>
### Sign in with phone
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
await supabase.auth.signIn(
phone: '+13334445555',
password: 'example-password',
);
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.auth.signInWithPassword(
phone: '+13334445555',
password: 'example-password',
);
```
</TabItem>
</Tabs>
### Sign in with phone using OTP
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
final res = await supabase.auth.signIn(phone: phone);
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.auth.signInWithOtp(
phone: phone,
);
// After receiving a SMS with a OTP.
await supabase.auth.verifyOTP(
type: OtpType.sms,
token: token,
phone: phone,
);
```
</TabItem>
</Tabs>
### Reset password for email
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
await supabase.auth.api.resetPasswordForEmail(
email,
options:
AuthOptions(redirectTo: 'io.supabase.flutter://reset-callback/'),
);
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.auth.resetPasswordForEmail(
email,
redirectTo: kIsWeb ? null : 'io.supabase.flutter://reset-callback/',
);
```
</TabItem>
</Tabs>
### Get the user's current session
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
final session = supabase.auth.session();
```
</TabItem>
<TabItem value="1.x">
```dart
final Session? session = supabase.auth.currentSession;
```
</TabItem>
</Tabs>
### Get the logged-in user
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
final user = supabase.auth.user();
```
</TabItem>
<TabItem value="1.x">
```dart
final User? user = supabase.auth.currentUser;
```
</TabItem>
</Tabs>
### Update user data for a logged-in user
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
await supabase.auth.update(
UserAttributes(data: {'hello': 'world'})
);
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.updateUser(
UserAttributes(
data: { 'hello': 'world' },
),
);
```
</TabItem>
</Tabs>
## Data methods
`.insert()` / `.upsert()` / `.update()` / `.delete()` don't return rows by default.
Previously, these methods return inserted/updated/deleted rows by default (which caused [some confusion](https://github.com/supabase/supabase/discussions/1548)), and you can opt to not return it by specifying `returning: 'minimal'`. Now the default behavior is to not return rows. To return inserted/updated/deleted rows, add a `.select()` call at the end.
Also, calling `.execute()` at the end of the query was a requirement in v0, but in v1 `.execute` is deperecated.
### Insert without returning inserted data
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
await supabase
.from('my_table')
.insert(data, returning: ReturningOption.minimal)
.execute();
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.from('my_table').insert(data);
```
</TabItem>
</Tabs>
### Insert with returning inserted data
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
final res = await supabase
.from('my_table')
.insert(data)
.execute();
```
</TabItem>
<TabItem value="1.x">
```dart
final insertedData = await supabase.from('my_table').insert(data).select();
```
</TabItem>
</Tabs>
## Realtime methods
### Stream
`.stream()` no longer needs the `.execute()` at the end. Also, filtering by `eq` is a lot easier now. `primaryKey` is now a named parameter to make it more obvious what to pass.
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
supabase.from('my_table:id=eq.120')
.stream(['id'])
.listen();
```
</TabItem>
<TabItem value="1.x">
```dart
supabase.from('my_table')
.stream(primaryKey: ['id'])
.eq('id', '120')
.listen();
```
</TabItem>
</Tabs>
### Subscribe
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
final subscription = supabase
.from('countries')
.on(SupabaseEventTypes.all, (payload) {
// Handle realtime payload
})
.subscribe();
```
</TabItem>
<TabItem value="1.x">
```dart
final channel = supabase.channel('*');
channel.on(
RealtimeListenTypes.postgresChanges,
ChannelFilter(event: '*', schema: '*'),
(payload, [ref]) {
// Handle realtime payload
},
).subscribe();
```
</TabItem>
</Tabs>
### Unsubscribe
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
supabase.removeSubscription(subscription);
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.removeChannel(channel);
```
</TabItem>
</Tabs>
@@ -1,25 +0,0 @@
---
id: intro
slug: /
sidebar_label: Supabase Dart Library
---
:::caution
You're viewing the docs for an older version of the `supabase-flutter` library.
:::
This reference documents every object and method available in Supabase's isomorphic Dart library, `supabase-dart`.
You can use the `supabase-dart` library to:
- interact with your Postgres database
- listen to database changes
- invoke Deno Edge Functions
- build login and user management functionality
- manage large files
## Additional Links
- Source Code: [github.com/supabase/supabase-dart](https://github.com/supabase/supabase-dart)
- [Known bugs and issues](https://github.com/supabase/supabase-dart/issues)
@@ -1,120 +0,0 @@
{
"sidebar": [
{
"type": "category",
"label": "Getting Started",
"items": ["intro", "generated/installing", "generated/initializing"],
"collapsed": true
},
{
"type": "category",
"label": "Auth",
"items": [
"generated/auth-signup",
"generated/auth-signin",
"generated/auth-signinwithprovider",
"generated/auth-signout",
"generated/auth-session",
"generated/auth-user",
"generated/auth-update",
"generated/auth-onauthstatechange",
"generated/reset-password-email"
],
"collapsed": true
},
{
"type": "category",
"label": "Functions",
"items": ["generated/invoke"],
"collapsed": true
},
{
"type": "category",
"label": "Database",
"items": [
"generated/select",
"generated/insert",
"generated/update",
"generated/upsert",
"generated/delete",
"generated/rpc"
],
"collapsed": true
},
{
"type": "category",
"label": "Realtime",
"items": [
"generated/subscribe",
"generated/removesubscription",
"generated/getsubscriptions",
"generated/stream"
],
"collapsed": true
},
{
"type": "category",
"label": "Storage",
"items": [
"generated/storage-createbucket",
"generated/storage-getbucket",
"generated/storage-listbuckets",
"generated/storage-updatebucket",
"generated/storage-deletebucket",
"generated/storage-emptybucket",
"generated/storage-from-upload",
"generated/storage-from-download",
"generated/storage-from-list",
"generated/storage-from-update",
"generated/storage-from-move",
"generated/storage-from-remove",
"generated/storage-from-createsignedurl",
"generated/storage-from-getpublicurl"
],
"collapsed": true
},
{
"type": "category",
"label": "Modifiers",
"items": [
"generated/using-modifiers",
"generated/limit",
"generated/order",
"generated/range",
"generated/single"
],
"collapsed": true
},
{
"type": "category",
"label": "Filters",
"items": [
"generated/using-filters",
"generated/or",
"generated/not",
"generated/match",
"generated/eq",
"generated/neq",
"generated/gt",
"generated/gte",
"generated/lt",
"generated/lte",
"generated/like",
"generated/ilike",
"generated/is_",
"generated/in_",
"generated/contains",
"generated/containedby",
"generated/rangelt",
"generated/rangegt",
"generated/rangegte",
"generated/rangelte",
"generated/rangeadjacent",
"generated/overlaps",
"generated/textsearch",
"generated/filter"
],
"collapsed": true
}
]
}
@@ -1 +0,0 @@
["v0"]
Whitespace-only changes.
@@ -1,37 +0,0 @@
---
id: installing
title: 'Installing'
slug: installing
custom_edit_url: https://github.com/supabase/supabase/edit/master/web/spec/supabase.yml
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
All JavaScript libraries are built directly by the Supabase team.
Other languages are built by the community and supported by Supabase.
## JavaScript
Via NPM
```bash
npm install @supabase/supabase-js
```
Via Yarn
```bash
yarn add @supabase/supabase-js
```
Find the source code on [GitHub](https://github.com/supabase/supabase-js).
Or via CDN
```js
<script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script>
//or
<script src="https://unpkg.com/@supabase/supabase-js@2"></script>
```
-25
View File
@@ -1,25 +0,0 @@
---
slug: /
sidebar_position: 1
sidebar_label: Supabase JavaScript Library
hide_table_of_contents: true
---
# Supabase JavaScript Library
This reference documents every object and method available in Supabase's isomorphic JavaScript library, `supabase-js`.
You can use the `supabase-js` library to:
- interact with your Postgres database
- listen to database changes
- invoke Deno Edge Functions
- build login and user management functionality
- manage large files
## Additional Links
- Source Code: [github.com/supabase/supabase-js](https://github.com/supabase/supabase-js)
- TypeDoc: [supabase.github.io/supabase-js](https://supabase.github.io/supabase-js/v2/)
- NPM: [npmjs.com/package/@supabase/supabase-js](https://www.npmjs.com/package/@supabase/supabase-js)
- [Known bugs and issues](https://github.com/supabase/supabase-js/issues)
@@ -1,213 +0,0 @@
---
id: release-notes
---
# Release Notes
Supabase.js v2 release notes.
## 2.0.0
Install the latest with `npm install @supabase/supabase-js`.
### Explicit constructor options
All client specific options within the constructor are keyed to the library: [PR](https://github.com/supabase/supabase-js/pull/458):
```jsx
const supabase = createClient(apiURL, apiKey, {
db: {
schema: 'public',
},
auth: {
storage: AsyncStorage,
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: true,
},
realtime: {
channels,
endpoint,
},
global: {
fetch: customFetch,
headers: DEFAULT_HEADERS,
},
})
```
### Typescript support
The libraries now support typescript.
```ts
// v2 - definitions are injected in `createClient()`
import type { Database } from './DatabaseDefinitions'
const supabase = createClient<Database>(SUPABASE_URL, ANON_KEY)
const { data } = await supabase.from('messages').select().match({ id: 1 })
// v1 -- previously definitions were injected in the `from()` method
supabase.from<Definitions['Message']>('messages').select('*')
```
Types can be generated via the CLI:
```bash
supabase start
supabase gen types typescript --local > DatabaseDefinitions.ts
```
### Data operations return minimal
`.insert()` / `.upsert()` / `.update()` / `.delete()` don't return rows by default: [PR](https://github.com/supabase/postgrest-js/pull/276).
Previously, these methods return inserted/updated/deleted rows by default (which caused [some confusion](https://github.com/supabase/supabase/discussions/1548)), and you can opt to not return it by specifying `returning: 'minimal'`. Now the default behavior is to not return rows. To return inserted/updated/deleted rows, add a `.select()` call at the end, e.g.:
```sql
const { data, error } = await supabase
.from('my_table')
.delete()
.eq('id', 1)
.select()
```
### New ordering defaults
`.order()` now defaults to Postgres’s default: [PR](https://github.com/supabase/postgrest-js/pull/283).
Previously `nullsFirst` defaults to `false` , meaning `null`s are ordered last. This is bad for performance if e.g. the column uses an index with `NULLS FIRST` (which is the default direction for indexes).
### Cookies and localstorage namespace
Storage key name in the Auth library has changed to include project reference which means that existing websites that had their JWT expiry set to a longer time could find their users logged out with this upgrade.
```jsx
const defaultStorageKey = `sb-${
new URL(this.authUrl).hostname.split('.')[0]
}-auth-token`
```
### New Auth Types
Typescript typings have been reworked. `Session` interface now guarantees that it will always have an `access_token`, `refresh_token` and `user`
```jsx
interface Session {
provider_token?: string | null
access_token: string
expires_in?: number
expires_at?: number
refresh_token: string
token_type: string
user: User
}
```
### New Auth methods
We're removing the `signIn()` method in favor of more explicit function signatures:
`signInWithPassword()`, `signInWithOtp()`, and `signInWithOtp()`.
```ts
// v2
const { data } = await supabase.auth.signInWithPassword({
email: 'hello@example',
password: 'pass',
})
// v1
const { data } = await supabase.auth.signIn({
email: 'hello@example',
password: 'pass',
})
```
### New Realtime methods
There is a new `channel()` method in the Realtime library, which will be used for our Multiplayer updates.
```ts
supabase
.channel('any_string_you_want')
.on('presence', { event: 'track' }, (payload) => {
console.log(payload)
})
.subscribe()
supabase
.channel('any_string_you_want')
.on(
'postgres_changes',
{
event: 'INSERT',
schema: 'public',
table: 'movies',
},
(payload) => {
console.log(payload)
}
)
.subscribe()
```
We will deprecate the `.from().on().subscribe()` method previously used for listening to postgres changes.
### Deprecated setAuth()
Deprecated and removed `setAuth()` . To set a custom `access_token` jwt instead, pass the custom header into the `createClient()` method provided: ([PR](https://github.com/supabase/gotrue-js/pull/340))
### All changes
- `supabase-js`
- `shouldThrowOnError` has been removed until all the client libraries support this option ([PR](https://github.com/supabase/supabase-js/pull/490)).
- `postgrest-js`
- TypeScript typings have been reworked [PR](https://github.com/supabase/postgrest-js/pull/279)
- Use `undefined` instead of `null` for function params, types, etc. (https://github.com/supabase/postgrest-js/pull/278)
- Some features are now obsolete: (https://github.com/supabase/postgrest-js/pull/275)
- filter shorthands (e.g. `cs` vs. `contains`)
- `body` in response (vs. `data`)
- `upsert`ing through the `.insert()` method
- `auth` method on `PostgrestClient`
- client-level `throwOnError`
- `gotrue-js`
- `supabase-js` client allows passing a `storageKey` param which will allow the user to set the key used in local storage for storing the session. By default, this will be namespace-d with the supabase project ref. ([PR](https://github.com/supabase/supabase-js/pull/460))
- `signIn` method is now split into `signInWithPassword` , `signInWithOtp` , `signInWithOAuth` ([PR](https://github.com/supabase/gotrue-js/pull/304))
- Deprecated and removed `session()` , `user()` in favor of using `getSession()` instead. `getSession()` will always return a valid session if a user is already logged in, meaning no more random logouts. ([PR](https://github.com/supabase/gotrue-js/pull/299))
- Deprecated and removed setting for `multitab` support because `getSession()` and gotrue’s reuse interval setting takes care of session management across multiple tabs ([PR](https://github.com/supabase/gotrue-js/pull/366))
- No more throwing of random errors, gotrue-js v2 always returns a custom error type: ([PR](https://github.com/supabase/gotrue-js/pull/341))
- `AuthSessionMissingError`
- Indicates that a session is expected but missing
- `AuthNoCookieError`
- Indicates that a cookie is expected but missing
- `AuthInvalidCredentialsError`
- Indicates that the incorrect credentials were passed
- Renamed the `api` namespace to `admin` , the `admin` namespace will only contain methods that should only be used in a trusted server-side environment with the service role key
- Moved `resetPasswordForEmail` , `getUser` and `updateUser` to the `GoTrueClient` which means they will be accessible from the `supabase.auth` namespace in `supabase-js` instead of having to do `supabase.auth.api` to access them
- Removed `sendMobileOTP` , `sendMagicLinkEmail` in favor of `signInWithOtp`
- Removed `signInWithEmail`, `signInWithPhone` in favor of `signInWithPassword`
- Removed `signUpWithEmail` , `signUpWithPhone` in favor of `signUp`
- Replaced `update` with `updateUser`
- `storage-js`
- Return types are more strict. Functions types used to indicate that the data returned could be null even if there was no error. We now make use of union types which only mark the data as null if there is an error and vice versa. ([PR](https://github.com/supabase/storage-js/pull/60))
- The `upload` and `update` function returns the path of the object uploaded as the `path` parameter. Previously the returned value had the bucket name prepended to the path which made it harder to pass the value on to other storage-js methods since all methods take the bucket name and path separately. We also chose to call the returned value `path` instead of `Key` ([PR](https://github.com/supabase/storage-js/pull/75))
- `getPublicURL` only returns the public URL inside the data object. This keeps it consistent with our other methods of returning only within the data object. No error is returned since this method cannot does not throw an error ([PR](https://github.com/supabase/storage-js/pull/93))
- signed urls are returned as `signedUrl` instead of `signedURL` in both `createSignedUrl` and `createSignedUrls` ([PR](https://github.com/supabase/storage-js/pull/94))
- Encodes URLs returned by `createSignedUrl`, `createSignedUrls` and `getPublicUrl` ([PR](https://github.com/supabase/storage-js/pull/86))
- `createsignedUrl` used to return a url directly and and within the data object. This was inconsistent. Now we always return values only inside the data object across all methods. ([PR](https://www.notion.so/LW5-supabase-js-v2-7b0bfcdf571d4f20b9b7a9308883f24b))
- `createBucket` returns a data object instead of the name of the bucket directly. ([PR](https://github.com/supabase/storage-js/pull/89))
- Fixed types for metadata ([PR](https://github.com/supabase/storage-js/pull/90))
- Better error types make it easier to track down what went wrong quicker.
- `SupabaseStorageClient` is no longer exported. Use `StorageClient` instead. ([PR](https://github.com/supabase/storage-js/pull/92)).
- `realtime-js`
- `RealtimeSubscription` class no longer exists and replaced by `RealtimeChannel`.
- `RealtimeClient`'s `disconnect` method now returns type of `void` . It used to return type of `Promise<{ error: Error | null; data: boolean }`.
- Removed `removeAllSubscriptions` and `removeSubscription` methods from `SupabaseClient` class.
- Removed `SupabaseRealtimeClient` class.
- Removed `SupabaseQueryBuilder` class.
- Removed `SupabaseEventTypes` type.
- Thinking about renaming this to something like `RealtimePostgresChangeEvents` and moving it to `realtime-js` v2.
- Removed `.from(’table’).on(’INSERT’, () ⇒ {}).subscribe()` in favor of new Realtime client API.
- `functions-js`
- supabase-js v1 only threw an error if the fetch call itself threw an error (network errors, etc) and not if the function returned HTTP errors like 400s or 500s. We have changed this behaviour to return an error if your function throws an error.
- We have introduced new error types to distinguish between different kinds of errors. A `FunctionsHttpError` error is returned if your function throws an error, `FunctionsRelayError` if the Supabase Relay has an error processing your function and `FunctionsFetchError` if there is a network error in calling your function.
- The correct content-type headers are automatically attached when sending the request if you don’t pass in a `Content-Type` header and pass in an argument to your function. We automatically attach the content type for `Blob`, `ArrayBuffer`, `File`, `FormData` ,`String` . If it doesn’t match any of these we assume the payload is `json` , we serialise the payload as JSON and attach the content type as `application/json`.
- `responseType` does not need to be explicitly passed in. We parse the response based on the `Content-Type` response header sent by the function. We support parsing the responses as `text`, `json`, `blob`, `form-data` and are parsed as `text` by default.
@@ -1,452 +0,0 @@
---
id: upgrade-guide
title: Upgrade to supabase-js v2
description: 'Learn how to upgrade to supabase-js v2.'
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
supabase-js v2 focuses on "quality-of-life" improvements for developers and addresses some of the largest pain points in v1. v2 includes type support, a rebuilt Auth library with async methods, improved errors, and more.
No new features will be added to supabase-js v1 , but we'll continuing merging security fixes to v1, with maintenance patches for the next 3 months.
## Upgrade the client library
```sh
npm install @supabase/supabase-js@2
```
*Optionally* if you are using custom configuration with `createClient` then follow below:
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts title="src/supabaseClient.ts"
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
schema: 'custom',
persistSession: false
})
```
</TabItem>
<TabItem value="2.x">
```ts title="src/supabaseClient.ts"
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
db: {
schema: 'custom'
},
auth: {
persistSession: true
}
})
```
</TabItem>
</Tabs>
Read more about the [constructor options](/docs/reference/javascript/release-notes#explicit-constructor-options).
### Auth methods
The signIn() method has been deprecated in favor of more explicit method signatures to help with type hinting. Previously it was difficult for developers to know what they were missing (e.g., a lot of developers didn't realize they could use passwordless magic links).
#### Sign in with email and password
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { user, error } = await supabase.auth.signIn({ email, password })
```
</TabItem>
<TabItem value="2.x">
```ts
const { data: { user }, error } = await supabase.auth.signInWithPassword({ email, password })
```
</TabItem>
</Tabs>
#### Sign in with magic link
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { error } = await supabase.auth.signIn({ email })
```
</TabItem>
<TabItem value="2.x">
```ts
const { error } = await supabase.auth.signInWithOtp({ email })
```
</TabItem>
</Tabs>
#### Sign in with a third-party provider
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { error } = await supabase.auth.signIn({ provider })
```
</TabItem>
<TabItem value="2.x">
```ts
const { error } = await supabase.auth.signInWithOAuth({ provider })
```
</TabItem>
</Tabs>
#### Sign in with phone
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { error } = await supabase.auth.signIn({ phone, password })
```
</TabItem>
<TabItem value="2.x">
```ts
const { error } = await supabase.auth.signInWithPassword({ phone, password })
```
</TabItem>
</Tabs>
#### Sign in with phone using OTP
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { error } = await supabase.auth.api.sendMobileOTP(phone)
```
</TabItem>
<TabItem value="2.x">
```ts
const { data, error } = await supabase.auth.signInWithOtp({ phone })
// After receiving a SMS with a OTP.
const { data, error } = await supabase.auth.verifyOtp({ phone, token })
```
</TabItem>
</Tabs>
#### Reset password for email
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { data, error } = await supabase.auth.api.resetPasswordForEmail(email)
```
</TabItem>
<TabItem value="2.x">
```ts
const { data, error } = await supabase.auth.resetPasswordForEmail(email)
```
</TabItem>
</Tabs>
#### Get the user's current session
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const session = supabase.auth.session()
```
</TabItem>
<TabItem value="2.x">
```ts
const { data: { session } } = await supabase.auth.getSession()
```
</TabItem>
</Tabs>
#### Get the logged-in user
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const user = supabase.auth.user()
```
</TabItem>
<TabItem value="2.x">
```ts
const { data: { session } } = await supabase.auth.getSession()
const { user } = session
```
</TabItem>
</Tabs>
#### Update user data for a logged-in user
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { user, error } = await supabase.auth.update({ attributes })
```
</TabItem>
<TabItem value="2.x">
```ts
const { data: { user }, error } = await supabase.auth.updateUser({ attributes })
```
</TabItem>
</Tabs>
#### Use a custom `access_token` JWT with Supabase
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { user, error } = supabase.auth.setAuth(access_token)
```
</TabItem>
<TabItem value="2.x">
```ts
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
global: {
headers: {
Authorization: `Bearer ${access_token}`
}
}
})
```
</TabItem>
</Tabs>
#### Cookie methods
The cookie related methods like `setAuthCookie` and `getUserByCookie` have been removed.
For Next.js you can use the [Auth Helpers](https://supabase.com/docs/guides/auth/auth-helpers/nextjs) to help you manage cookies.
If you can't use the Auth Helpers, you can follow [this approach](https://supabase.com/docs/guides/auth/server-side-rendering) for server-side rendering.
Some more background information about the reasoning can be obtained [here](https://github.com/supabase/gotrue-js/pull/340).
### Data methods
`.insert()` / `.upsert()` / `.update()` / `.delete()` don't return rows by default: [PR](https://github.com/supabase/postgrest-js/pull/276).
Previously, these methods return inserted/updated/deleted rows by default (which caused [some confusion](https://github.com/supabase/supabase/discussions/1548)), and you can opt to not return it by specifying `returning: 'minimal'`. Now the default behavior is to not return rows. To return inserted/updated/deleted rows, add a `.select()` call at the end.
#### Insert and return data
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { data, error } = await supabase.auth.insert({ new_data })
```
</TabItem>
<TabItem value="2.x">
```ts
const { data, error } = await supabase.auth.insert({ new_data }).select()
```
</TabItem>
</Tabs>
#### Update and return data
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const { data, error } = await supabase.auth.update({ new_data }).eq('id', id)
```
</TabItem>
<TabItem value="2.x">
```ts
const { data, error } = await supabase.auth.update({ new_data }).eq('id', id).select()
```
</TabItem>
</Tabs>
### Realtime methods
#### Subscribe
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
const userListener = supabase.from('users')
.on('*',
(payload) => handleAllEventsPayload(payload.new)
)
.subscribe()
```
</TabItem>
<TabItem value="2.x">
```ts
const userListener = supabase.channel('all-users-changes')
.on(
'postgres_changes',
{ event: '*', schema: 'public', table: 'user' },
(payload) => handleAllEventsPayload()
)
.subscribe()
```
</TabItem>
</Tabs>
#### Unsubscribe
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
userListener.unsubscribe()
```
</TabItem>
<TabItem value="2.x">
```ts
supabase.removeChannel(userListener)
```
</TabItem>
</Tabs>
#### onOpen
<Tabs
groupId="version"
values={[
{label: 'Before', value: '1.x'},
{label: 'After', value: '2.x'},
]}>
<TabItem value="1.x">
```ts
supabase.realtime.onOpen(() => console.log('Connected to socket'))
```
</TabItem>
<TabItem value="2.x">
```ts
supabase.channel('any')
.subscribe((status) => {
if (status === 'SUBSCRIBED') {
console.log('Connected to channel')
}
})
```
</TabItem>
</Tabs>
@@ -1,100 +0,0 @@
---
id: typescript-support
---
# Typescript Support
`supabase-js` supports Typescript.
## Generating types
You can use the [Supabase CLI](/docs/guides/cli) to generate types directly from your Postgres database’s schema:
### Generate types from a remote database
Install the [Supabase CLI](/docs/guides/cli#installation) locally, and then run:
```bash
supabase login
supabase projects list
supabase gen types typescript --project-id <project_id> > lib/database.types.ts
```
### Generate types from a local database
Set up your [local development environment](/docs/guides/cli/local-development), and then run:
```bash
supabase start
supabase gen types typescript --local > lib/database.types.ts
```
For additional methods, see the [CLI Reference Docs](/docs/reference/cli/usage#supabase-gen-types).
These types are generated directly from your database. Given a table `public.movies`, the definition will provide the following data:
```ts
interface Database {
public: {
Tables: {
movies: {
Row: {} // The data expected to be returned from a "select" statement.
Insert: {} // The data expected passed to an "insert" statement.
Update: {} // The data expected passed to an "update" statement.
}
}
}
}
```
There is a difference between `selects`, `inserts`, and `updates`, because often you will set default values in your database for specific columns.
With default values you do not need to send any data over the network, even if that column is a "required" field. Our type system is granular
enough to handle these situations.
## Injecting type definitions
You can enrich the supabase client with the types you generated with Supabase.
```ts
import { createClient } from '@supabase/supabase-js'
import { Database } from 'lib/database.types'
const supabase = createClient<Database>(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY
)
```
## Type hints
`supabase-js` always returns a `data` object (for success), and an `error` response (for unsuccessful requests).
This provides a simple interface to get the relevant types returned from any function:
```ts
export async function getMovies() {
return await supabase.from('movies').select(`id, title`)
}
type MoviesResponse = Awaited<ReturnType<typeof getMovies>>
export type MoviesResponseSuccess = MoviesResponse['data']
export type MoviesResponseError = MoviesResponse['error']
```
## Nested tables
For advanced queries such as nested tables, you may want to construct your own types.
```ts
import supabase from '~/lib/supabase'
import type { Database } from '~/lib/database.types'
async function getMovies() {
return await supabase.from('movies').select('id, title, actors(*)')
}
type Actors = Database['public']['Tables']['actors']['Row']
type MoviesResponse = Awaited<ReturnType<typeof getMovies>>
type MoviesResponseSuccess = MoviesResponse['data'] & {
actors: Actors[]
}
```
Whitespace-only changes.
@@ -1,42 +0,0 @@
---
id: generating-types
title: 'Generating Types'
slug: generating-types
custom_edit_url: https://github.com/supabase/supabase/edit/master/spec/supabase_js_v1.yml
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
Supabase will soon release native type generators that dump your database types for various languages. For now, we support TypeScript [through third-party tools](/docs/guides/api/generating-types).
## Usage with TypeScript
`supabase-js` ships with type definitions for usage with TypeScript and for convenient IntelliSense auto-complete and documentation in your editor.
When using TypeScript, you can pass the type of database row as a type parameter to the `from` method to get better auto-completion support down the chain.
If you don't provide a type for the row you need to explicitly pass `from<any>('tableName')`.
```ts
type Message = {
id: number
inserted_at: string
message: string
user_id: string
channel_id: number
author: { username: string }
}
const response = await supabase
.from<Message>('messages') // Message maps to the type of the row in your database.
.select('*, author:user_id(username)')
.match({ channel_id: 2 }) // Your IDE will be able to help with auto-completion.
response.data // Response data will be of type Array<Message>.
// If you don't provide a type for the row you need to explicitly pass `from<any>('tableName')`.
const response = await supabase
.from<any>('messages')
.select('*, author:user_id(username)')
.match({ channel_id: 2 })
response.data // Response data will be of type Array<any>.
```
@@ -1,11 +0,0 @@
---
id: index
title: 'Supabase Client'
slug: supabase-client
custom_edit_url: ../../spec/supabase_js_v1.yml
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
Supabase JavaScript.
@@ -1,151 +0,0 @@
---
id: initializing
title: 'Initializing'
slug: initializing
custom_edit_url: https://github.com/supabase/supabase/edit/master/spec/supabase_js_v1.yml
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
You can initialize a new Supabase client using the `createClient()` method.
The Supabase client is your entrypoint to the rest of the Supabase functionality
and is the easiest way to interact with everything we offer within the Supabase ecosystem.
## Parameters
<ul className="method-list-group">
<li className="method-list-item">
<h4 className="method-list-item-label">
<span className="method-list-item-label-name">
supabaseUrl
</span>
<span className="method-list-item-label-badge required">
required
</span>
<span className="method-list-item-validation">
<code>string</code>
</span>
</h4>
<div class="method-list-item-description">
The unique Supabase URL which is supplied when you create a new project in your project dashboard.
</div>
</li>
<li className="method-list-item">
<h4 className="method-list-item-label">
<span className="method-list-item-label-name">
supabaseKey
</span>
<span className="method-list-item-label-badge required">
required
</span>
<span className="method-list-item-validation">
<code>string</code>
</span>
</h4>
<div class="method-list-item-description">
The unique Supabase Key which is supplied when you create a new project in your project dashboard.
</div>
</li>
<li className="method-list-item">
<h4 className="method-list-item-label">
<span className="method-list-item-label-name">
options
</span>
<span className="method-list-item-label-badge false">
optional
</span>
<span className="method-list-item-validation">
<code>SupabaseClientOptions</code>
</span>
</h4>
<div class="method-list-item-description">
No description provided.
</div>
</li>
</ul>
## Examples
### createClient()
```js
import { createClient } from '@supabase/supabase-js'
// Create a single supabase client for interacting with your database
const supabase = createClient(
'https://xyzcompany.supabase.co',
'public-anon-key'
)
```
### With additional parameters
```js
import { createClient } from '@supabase/supabase-js'
const options = {
schema: 'public',
headers: { 'x-my-custom-header': 'my-app-name' },
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: true,
}
const supabase = createClient(
'https://xyzcompany.supabase.co',
'public-anon-key',
options
)
```
### API schemas
```js
import { createClient } from '@supabase/supabase-js'
// Provide a custom schema. Defaults to "public".
const supabase = createClient(
'https://xyzcompany.supabase.co',
'public-anon-key',
{
schema: 'other_schema',
}
)
```
By default the API server points to the `public` schema. You can enable other database schemas within the Dashboard.
Go to `Settings > API > Schema` and add the schema which you want to expose to the API.
Note: each client connection can only access a single schema, so the code above can access the `other_schema` schema but cannot access the `public` schema.
### Custom `fetch` implementation
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
'https://xyzcompany.supabase.co',
'public-anon-key',
{
fetch: fetch.bind(globalThis),
}
)
```
`supabase-js` uses the [`cross-fetch`](https://www.npmjs.com/package/cross-fetch) library to make HTTP requests,
but an alternative `fetch` implementation can be provided as an option.
This is most useful in environments where `cross-fetch` is not compatible (for instance Cloudflare Workers).
@@ -1,37 +0,0 @@
---
id: installing
title: 'Installing'
slug: installing
custom_edit_url: https://github.com/supabase/supabase/edit/master/spec/supabase_js_v1.yml
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
All JavaScript libraries are built directly by the Supabase team.
Other languages are built by the community and supported by Supabase.
## JavaScript
Via NPM
```bash
npm install @supabase/supabase-js
```
Via Yarn
```bash
yarn add @supabase/supabase-js
```
Find the source code on [GitHub](https://github.com/supabase/supabase-js).
Or via CDN
```js
<script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@1"></script>
//or
<script src="https://unpkg.com/@supabase/supabase-js@1"></script>
```
@@ -1,20 +0,0 @@
---
id: intro
title: 'Supabase JavaScript Library'
slug: /
sidebar_label: Supabase JavaScript Library
---
:::caution
You're viewing the docs for an older version of the `supabase-js` library.
:::
This reference documents every object and method available in Supabase's isomorphic JavaScript library, `supabase-js`.
You can use the `supabase-js` library to:
- interact with your Postgres database
- listen to database changes
- invoke Deno Edge Functions
- build login and user management functionality
- manage large files
Whitespace-only changes.
@@ -1,138 +0,0 @@
{
"sidebar": [
{
"type": "category",
"label": "Getting Started",
"items": ["intro", "installing", "initializing", "generating-types"],
"collapsed": false
},
{
"type": "category",
"label": "Auth",
"items": [
"generated/auth-signup",
"generated/auth-signin",
"generated/auth-signout",
"generated/auth-session",
"generated/auth-user",
"generated/auth-update",
"generated/auth-setauth",
"generated/auth-onauthstatechange",
"generated/auth-api-getuser",
"generated/auth-api-resetpasswordforemail"
],
"collapsed": true
},
{
"type": "category",
"label": "Auth (Server Only)",
"items": [
"generated/auth-api-listusers",
"generated/auth-api-createuser",
"generated/auth-api-deleteuser",
"generated/auth-api-generatelink",
"generated/auth-api-inviteuserbyemail",
"generated/auth-api-sendmobileotp",
"generated/auth-api-updateuserbyid"
],
"collapsed": true
},
{
"type": "category",
"label": "Functions",
"items": ["generated/invoke"],
"collapsed": true
},
{
"type": "category",
"label": "Database",
"items": [
"generated/select",
"generated/insert",
"generated/update",
"generated/upsert",
"generated/delete",
"generated/rpc"
],
"collapsed": true
},
{
"type": "category",
"label": "Realtime",
"items": [
"generated/subscribe",
"generated/removesubscription",
"generated/removeallsubscriptions",
"generated/getsubscriptions"
],
"collapsed": true
},
{
"type": "category",
"label": "Storage",
"items": [
"generated/storage-createbucket",
"generated/storage-getbucket",
"generated/storage-listbuckets",
"generated/storage-updatebucket",
"generated/storage-deletebucket",
"generated/storage-emptybucket",
"generated/storage-from-upload",
"generated/storage-from-download",
"generated/storage-from-list",
"generated/storage-from-update",
"generated/storage-from-move",
"generated/storage-from-copy",
"generated/storage-from-remove",
"generated/storage-from-createsignedurl",
"generated/storage-from-createsignedurls",
"generated/storage-from-getpublicurl"
],
"collapsed": true
},
{
"type": "category",
"label": "Modifiers",
"items": [
"generated/using-modifiers",
"generated/limit",
"generated/order",
"generated/range",
"generated/single",
"generated/maybesingle"
],
"collapsed": true
},
{
"type": "category",
"label": "Filters",
"items": [
"generated/using-filters",
"generated/or",
"generated/not",
"generated/match",
"generated/eq",
"generated/neq",
"generated/gt",
"generated/gte",
"generated/lt",
"generated/lte",
"generated/like",
"generated/ilike",
"generated/is",
"generated/in",
"generated/contains",
"generated/containedby",
"generated/rangelt",
"generated/rangegt",
"generated/rangegte",
"generated/rangelte",
"generated/rangeadjacent",
"generated/overlaps",
"generated/textsearch",
"generated/filter"
],
"collapsed": true
}
]
}
@@ -1 +0,0 @@
["v1"]
-3
View File
@@ -1,3 +0,0 @@
module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
}
-189
View File
@@ -1,189 +0,0 @@
---
id: about
title: Introduction
description: 'What is Supabase?'
slug: /
hide_table_of_contents: true
pagination_next: null
---
import ThemedImage from '@theme/ThemedImage'
import AngularLogo from '@site/static/img/libraries/angular-icon.svg'
import ExpoLogo from '@site/static/img/libraries/expo-icon.svg'
import FlutterLogo from '@site/static/img/libraries/flutter-icon.svg'
import JavascriptLogo from '@site/static/img/libraries/javascript-icon.svg'
import NextjsDarkLogo from '@site/static/img/libraries/nextjs-dark-icon.svg'
import NextjsLightLogo from '@site/static/img/libraries/nextjs-light-icon.svg'
import ReactLogo from '@site/static/img/libraries/react-icon.svg'
import SolidJSLogo from '@site/static/img/libraries/solidjs-icon.svg'
import RedwoodJsLogo from '@site/static/img/libraries/redwoodjs-icon.svg'
import SvelteLogo from '@site/static/img/libraries/svelte-icon.svg'
import VuejsLogo from '@site/static/img/libraries/vuejs-icon.svg'
import useBaseUrl from '@docusaurus/useBaseUrl'
import Link from '@docusaurus/Link'
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
import ButtonCard from '@site/src/components/ButtonCard'
const frameworks = [
{
name: 'Angular',
logo: AngularLogo,
href: '/guides/with-angular',
},
{
name: 'Expo',
logo: ExpoLogo,
href: '/guides/with-expo',
},
{ name: 'Flutter', logo: FlutterLogo, href: '/guides/with-flutter' },
{
name: 'JavaScript',
logo: JavascriptLogo,
href: '/reference/javascript/installing#javascript',
},
{
name: 'Next.js',
themed: true,
logo: {
dark: '/img/libraries/nextjs-dark-icon.svg',
light: '/img/libraries/nextjs-light-icon.svg',
},
href: '/guides/with-nextjs',
},
{ name: 'React', logo: ReactLogo, href: '/guides/with-react' },
{
name: 'RedwoodJS',
logo: RedwoodJsLogo,
href: '/guides/with-redwoodjs',
},
{ name: 'SolidJS', logo: SolidJSLogo, href: '/guides/with-solidjs' },
{ name: 'Svelte', logo: SvelteLogo, href: '/guides/with-svelte' },
{ name: 'Vue', logo: VuejsLogo, href: '/guides/with-vue-3' },
]
Supabase is an open source Firebase alternative providing all the backend features you need to build a product.
You can use it completely, or just the features you need.
[Start a project](https://app.supabase.com) with the hosted platform or learn how to [host Supabase](/docs/guides/hosting/overview) yourself.
## Learn about features
<div class="container" style={{ padding: 0 }}>
<div class="row is-multiline">
{/* Auth */}
<div class="col col--4">
<ButtonCard
class="card"
to={useBaseUrl('/guides/auth')}
title={'Auth'}
description={'User management with Row Level Security.'}
style={{ height: '100%' }}
/>
</div>
{/* Auto-generated APIs */}
<div class="col col--4">
<ButtonCard
class="card"
to={useBaseUrl('/guides/api')}
title={'Auto-generated APIs'}
description={'Instantly generate APIs for your database.'}
style={{ height: '100%' }}
/>
</div>
{/* Database */}
<div class="col col--4">
<ButtonCard
class="card"
to={useBaseUrl('/guides/database')}
title={'Database'}
description={'A dedicated, scalable Postgres database.'}
style={{ height: '100%' }}
/>
</div>
{/* Edge Functions */}
<div class="col col--4">
<ButtonCard
class="card"
to={useBaseUrl('/guides/functions')}
title={'Edge Functions'}
description={'Server-side functions, distributed globally.'}
style={{ height: '100%' }}
/>
</div>
{/* Realtime */}
<div class="col col--4">
<ButtonCard
class="card"
to={useBaseUrl('/guides/realtime')}
title={'Realtime'}
description={'Build with Broadcast, Presence, and Postgres CDC.'}
style={{ height: '100%' }}
/>
</div>
{/* File Storage */}
<div class="col col--4">
<ButtonCard
class="card"
to={useBaseUrl('/guides/storage')}
title={'File Storage'}
description={'Store, organize, and serve large files.'}
style={{ height: '100%' }}
/>
</div>
{/* Observability */}
<div class="col col--4">
<ButtonCard
class="card"
to={useBaseUrl('/guides/platform/logs')}
title={'Observability'}
description={'Monitor and debug your infrastucture.'}
style={{ height: '100%' }}
/>
</div>
</div>
</div>
## Start with a framework
Supabase is just Postgres, which makes it compatible with a large number of tools and frameworks.
<div>
<div class="row is-multiline">
{frameworks.map((x) => (
<div key={x.name} class="col col--3">
<ButtonCard
layout="horizontal"
icon={
x.logo && !x.themed ? (
<x.logo
width="20"
alt={x.name}
style={{ display: 'block', maxHeight: 20, minWidth: 20 }}
/>
) : (
<ThemedImage
style={{
display: 'block',
maxHeight: 20,
minWidth: 20,
margin: 0,
}}
alt={x.name}
width="20"
sources={{
light: useBaseUrl(x.logo.light),
dark: useBaseUrl(x.logo.dark),
}}
/>
)
}
class="card"
to={useBaseUrl(x.href)}
title={x.name}
description={x.description}
style={{ height: '100%' }}
/>
</div>
))}
</div>
</div>
-156
View File
@@ -1,156 +0,0 @@
---
id: architecture
title: Architecture
description: 'Supabase design and architecture'
---
Supabase is open source. We choose open source tools which are scalable and make them simple to use.
Supabase is not a 1-to-1 mapping of Firebase. While we are building many of the features that Firebase offers, we are not going about it the same way:
our technological choices are quite different; everything we use is open source; and wherever possible, we use and support existing tools rather than developing from scratch.
Most notably, we use Postgres rather than a NoSQL store. This choice was deliberate. We believe that no other database offers the functionality required to compete with Firebase,
while maintaining the scalability required to go beyond it.
## Architecture
Each Supabase project consists of several tools:
![Supabase Architecture](/img/supabase-architecture.png)
### PostgreSQL (Database)
PostgreSQL is the core of Supabase. We do not abstract the PostgreSQL database — you can access it and use it with full privileges. We simply provide tools which makes PostgreSQL as easy to use as Firebase.
- Official Docs: [postgresql.org/docs](https://www.postgresql.org/docs/current/index.html)
- Source code: [github.com/postgres/postgres](https://github.com/postgres/postgres) (mirror)
- License: [PostgreSQL Licence](https://www.postgresql.org/about/licence/)
- Language: C
### Studio (Dashboard)
An open source Dashboard for managing your database and services.
- Official Docs: [Supabase docs](/docs)
- Source code: [github.com/supabase/supabase](https://github.com/supabase/supabase/tree/master/studio)
- License: [Apache 2](https://github.com/supabase/supabase/blob/master/LICENSE)
- Language: TypeScript
### GoTrue (Auth)
A JWT-based API for managing users and issuing access tokens. This integrates with PostgreSQL's Row Level Security and the API servers.
- Official Docs: [Supabase Auth reference docs](/docs/reference/auth)
- Source code: [github.com/supabase/gotrue](https://github.com/supabase/gotrue)
- License: [MIT](https://github.com/supabase/gotrue/blob/master/LICENSE)
- Language: Go
### PostgREST (API)
A standalone web server that turns your PostgreSQL database directly into a RESTful API.
We use this with our [pg_graphql](https://github.com/supabase/pg_graphql) extension to provide a GraphQL API.
- Official Docs: [postgrest.org](https://postgrest.org/)
- Source code: [github.com/PostgREST/postgrest](https://github.com/PostgREST/postgrest)
- License: [MIT](https://github.com/PostgREST/postgrest/blob/main/LICENSE)
- Language: Haskel
### Realtime (API & multiplayer)
A scalable websocket engine for managing user Presence, broadcasting messages, and streaming database changes.
- Official Docs: [Supabase Realtime docs](/docs/guides/realtime)
- Source code: [github.com/supabase/realtime](https://github.com/supabase/realtime)
- License: [Apache 2](https://github.com/supabase/realtime/blob/master/LICENSE)
- Language: Elixir
### Storage API (large file storage)
An S3-compatible object storage service that stores metadata in Postgres.
- Official Docs: [Supabase Storage reference docs](/docs/reference/storage)
- Source code: [github.com/supabase/storage-api](https://github.com/supabase/storage-api)
- License: [Apache 2.0](https://github.com/supabase/storage-api/blob/master/LICENSE)
- Language: NodeJS / TypeScript
### Deno (Edge Functions)
A modern runtime for JavaScript and TypeScript.
- Official Docs: [deno.land](https://deno.land/)
- Source code: [github.com/denoland/deno](https://github.com/denoland/deno)
- License: [MIT](https://github.com/denoland/deno/blob/main/LICENSE.md)
- Language: TypeScript / Rust
### postgres-meta (Database management)
A RESTful API for managing your Postgres. Fetch tables, add roles, and run queries.
- Official Docs: [supabase.github.io/postgres-meta](https://supabase.github.io/postgres-meta/)
- Source code: [github.com/supabase/postgres-meta](https://github.com/supabase/postgres-meta)
- License: [Apache 2.0](https://github.com/supabase/postgres-meta/blob/master/LICENSE)
- Language: NodeJS / TypeScript
### PgBouncer
A lightweight connection pooler for PostgreSQL. This is useful for connecting to Postgres when using Serverless functions.
- Official Docs: [pgbouncer.org](http://www.pgbouncer.org/)
- Source code: [pgbouncer/pgbouncer](https://github.com/pgbouncer/pgbouncer)
- License: [ISC](https://github.com/pgbouncer/pgbouncer/blob/master/COPYRIGHT)
- Language: C
### Kong (API Gateway)
A cloud-native API gateway, built on top of Nginx.
- Official Docs: [docs.konghq.com](https://docs.konghq.com/)
- Source code: [github.com/kong/kong](https://github.com/kong/kong)
- License: [Apache 2.0](https://github.com/Kong/kong/blob/master/LICENSE)
- Language: Lua
## Product Principles
It is our goal to provide an architecture that any large-scale company would design for themselves,
and then provide tooling around that architecture that is easy-to-use for indie-developers and small teams.
We use a series of principles to ensure that scalability and usability are never mutually exclusive:
### Everything works in isolation
Each system must work as a standalone tool with as few moving parts as possible.
The litmus test for this is: "Can a user run this product with nothing but a Postgres database?"
### Everything is integrated
Supabase is composable. Even though every product works in isolation, each product on the platform needs to 10x the other products.
For integration, each tool should expose an API and Webhooks.
### Everything is extensible
We're deliberate about adding a new tool, and prefer instead to extend an existing one.
This is the opposite of many cloud providers whose product offering expands into niche use-cases. We provide _primitives_ for developers, which allow them to achieve any goal.
Less, but better.
### Everything is portable
To avoid lock-in, we make it easy to migrate in and out. Our cloud offering is compatible with our self-hosted product.
We use existing standards to increase portability (like pg_dump an CSV files). If a new standard emerges which competes with a "Supabase" approach, we will deprecate the approach in favor of the standard.
This forces us compete on experience. We aim to be the best Postgres hosting service.
### Play the long game
We sacrifice short-term wins for long-term gains. For example, it is tempting to run a fork of Postgres with additional functionality which only our customers need.
Instead, we prefer to support efforts to upstream missing functionality so that the entire community benefits. This has the additional benefit of ensuring portability and longevity.
### Build for developers
"Developers" are a specific profile of user: they are _builders_.
When assessing impact as a function of effort, developers have a large efficiency due to the type of products and systems they can build.
As the profile of a developer changes over time, Supabase will continue to evolve the product to fit this evolving profile.
### Support existing tools
Supabase supports existing tools and communities wherever possible. Supabase is more like a "community of communities" - each tool typically has its own community
which we work with.
Open source is something we approach [collaboratively](https://supabase.com/blog/supabase-series-b#giving-back): we employ maintainers, sponsor projects, invest in businesses, and develop our own open source tools.
-52
View File
@@ -1,52 +0,0 @@
---
id: aup
title: Acceptable Use Policy
---
`Last Modified: 15 April 2021`
This Acceptable Use Policy (this “Policy”) describes prohibited uses of the web services offered by Supabase, Inc. and its affiliates (the “Services”) and the website located at https://supabase.com (the “Supabase Site”). The examples described in this Policy are not exhaustive. We may modify this Policy at any time by posting a revised version on the Supabase Site. By using the Services or accessing the Supabase Site, you agree to the latest version of this Policy. If you violate the Policy or authorize or help others to do so, we may suspend or terminate your use of the Services.
## No Illegal, Harmful, or Offensive Use or Content
You may not use, or encourage, promote, facilitate or instruct others to use, the Services or Supabase Site for any illegal, harmful, fraudulent, infringing or offensive use, or to transmit, store, display, distribute or otherwise make available content that is illegal, harmful, fraudulent, infringing or offensive. Prohibited activities or content include:
- **Illegal, Harmful or Fraudulent Activities.** Any activities that are illegal, that violate the rights of others, or that may be harmful to others, our operations or reputation, including disseminating, promoting or facilitating child pornography, offering or disseminating fraudulent goods, services, schemes, or promotions, make-money-fast schemes, ponzi and pyramid schemes, phishing, or pharming.
- **Infringing Content.** Content that infringes or misappropriates the intellectual property or proprietary rights of others.
- **Offensive Content.** Content that is defamatory, obscene, abusive, invasive of privacy, or otherwise objectionable, including content that constitutes child pornography, relates to bestiality, or depicts non-consensual sex acts.
- **Harmful Content.** Content or other computer technology that may damage, interfere with, surreptitiously intercept, or expropriate any system, program, or data, including viruses, Trojan horses, worms, time bombs, or cancelbots.
- **Platform compliance.** Any activities that are deemed unacceptable by the platforms used by the Supabase Site and Services, including [AWS](https://aws.amazon.com/aup/).
## No Security Violations
You may not use the Services to violate the security or integrity of any network, computer or communications system, software application, or network or computing device (each, a “System”). Prohibited activities include:
- **Unauthorized Access.** Accessing or using any System without permission, including attempting to probe, scan, or test the vulnerability of a System or to breach any security or authentication measures used by a System.
- **Interception.** Monitoring of data or traffic on a System without permission.
- **Falsification of Origin.** Forging TCP-IP packet headers, e-mail headers, or any part of a message describing its origin or route. The legitimate use of aliases and anonymous remailers is not prohibited by this provision.
## No Network Abuse
You may not make network connections to any users, hosts, or networks unless you have permission to communicate with them. Prohibited activities include:
- **Monitoring or Crawling.** Monitoring or crawling of a System that impairs or disrupts the System being monitored or crawled.
- **Denial of Service (DoS).** Inundating a target with communications requests so the target either cannot respond to legitimate traffic or responds so slowly that it becomes ineffective.
- **Intentional Interference.** Interfering with the proper functioning of any System, including any deliberate attempt to overload a system by mail bombing, news bombing, broadcast attacks, or flooding techniques.
- **Operation of Certain Network Services.** Operating network services like open proxies, open mail relays, or open recursive domain name servers.
- **Avoiding System Restrictions.** Using manual or electronic means to avoid any use limitations placed on a System, such as access and storage restrictions.
## No E-Mail or Other Message Abuse
You will not distribute, publish, send, or facilitate the sending of unsolicited mass e-mail or other messages, promotions, advertising, or solicitations (like “spam”), including commercial advertising and informational announcements. You will not alter or obscure mail headers or assume a sender’s identity without the sender’s explicit permission. You will not collect replies to messages sent from another internet service provider if those messages violate this Policy or the acceptable use policy of that provider.
## Our Monitoring and Enforcement
We reserve the right, but do not assume the obligation, to investigate any violation of this Policy or misuse of the Services or Supabase Site. We may:
- investigate violations of this Policy or misuse of the Services or Supabase Site; or
- remove, disable access to, or modify any content or resource that violates this Policy or any other agreement we have with you for use of the Services or the Supabase Site.
We may report any activity that we suspect violates any law or regulation to appropriate law enforcement officials, regulators, or other appropriate third parties. Our reporting may include disclosing appropriate customer information. We also may cooperate with appropriate law enforcement agencies, regulators, or other appropriate third parties to help with the investigation and prosecution of illegal conduct by providing network and systems information related to alleged violations of this Policy.
Reporting of Violations of this Policy
If you become aware of any violation of this Policy, you will immediately notify us and provide us with assistance, as requested, to stop or remedy the violation. To report any violation of this Policy, please contact us at support@supabase.io.
-292
View File
@@ -1,292 +0,0 @@
---
id: privacy
title: Privacy Policy
---
`Last modified: 27 March 2021`
Thank you for your interest in Supabase, Inc., ("**_Supabase_**," "**_we_**", "**_our_**" or "**_us_**"). Supabase provides a suite of open source tools, stitched together to build a seamless developer experience. This Privacy Notice explains how information about you, that directly identifies you, or that makes you identifiable ("**_personal information_**") is collected, used and disclosed by Supabase in connection with our website at [supabase.com](https://supabase.com) (the "**_Site_**") and our services offered in connection with the Site (collectively with the Site, the "**_Service_**").
We may also provide you with additional privacy notices or disclosures where the scope of the inquiry, request, or personal information we require falls outside the scope of this Privacy Notice. In that case, the additional Privacy Notice or disclosures will govern how we may process the information you provide at that time. Please note that this Privacy Notice does not cover or apply to our processing of information about our employees or contractors.
This Policy explains how we use your personal information when we act as a data controller. As far as you use our Service as a natural person, we are the controller of your personal information. We are responsible for, and control, the processing of your personal information.
Wherever our customers use our Service to submit, manage, or otherwise use content relating to our customers’ end users ("**_Customer Data_**") during the provision of our Service, we have contractually committed ourselves to only process such information on behalf and under the instruction of the respective customer, who is the data controller. This Privacy Notice does not apply to such processing and we recommend you read the Privacy Notice of the respective customer, if their processing concerns your personal information.
## Region-specific Disclosures
- **California - Your California Privacy Rights:** If you are a California resident, California Civil Code Section 1798.83 permits you to request information regarding the disclosure of personal information to third parties for their direct marketing purposes during the immediately preceding calendar year. Note we do not share your personal information with third parties for their own marketing purposes.
- **Nevada:** Chapter 603A of the Nevada Revised Statutes permits a Nevada resident to opt out of future sales of certain covered information that a website operator has collected or will collect about the resident. Note we do not sell your personal information within the meaning of Chapter 603A. However, if you would still like to submit such a request, please contact us at support@supabase.io.
- **European Economic Area, United Kingdom or Switzerland:** If you are located in the European Economic Area ("**_EEA_**"), United Kingdom or Switzerland, or otherwise engage with Supabase’s European operations, please see the **Privacy Disclosures for the European Economic Area, United Kingdom and Switzerland** for additional European-specific privacy disclosures, including what constitutes your personal information, the lawful bases we rely on to process your personal information, how we use cookies when you access our Sites from the EEA, UK or Switzerland and your rights in respect of your personal information.
**Note for International Visitors:** Personal information may be transferred to, stored and processed in a country other than the one in which it was collected. For example, the Sites are primarily hosted in and provided from the United States. Please note the country to which personal data is transferred may not provide the same level of protection for personal information as the country from which it was transferred.
## 1. Information we collect and our use
We collect personal information in connection with your visits to and use of the Service. This collection includes information that you provide in connection with the Service, information from third parties, and information that is collected automatically such as through the use of cookies and other technologies.
### Information That You Provide
We collect personal information from you. The categories of information we collect can include:
- **_Registration information._** We collect personal and/or business information that you provide when you register for an account at the Site. This information may include your name, email address, GitHub username. We use this information to administer your account, provide you with the relevant services and information, communicate with you regarding your account, the Site and for customer support purposes.
- **_Information collected through the Use of the Service._** After registration, you may create, upload or transmit files, documents, videos, images, data or information as part of your use of the Service (collectively, "**_User Content_**"). User Content and any information contained in the User Content, including personal information you may have included, is stored and collected as part of the Service. You have full control of the information included in the User Content.
- **_Payment information._** If you make a purchase or payment on the Site, such as for a subscription, we collect transactional information provided in connection with your purchase or payment. Please note that we use third party payment processors, including Stripe, to process payments made to us. As such, we do not retain any personally identifiable financial information such as credit card numbers. Rather, all such information is provided directly by you to our third-party processor. The payment processor’s use of your personal information is governed by their privacy notice. To view Stripe’s privacy notice, please visit: <https://stripe.com/privacy>.
- **_Communications._** If you communicate with us through any paper or electronic form, we may collect your name, email address, mailing address, phone number, or any other personal information you choose to provide to us. We use this information to investigate and respond to your inquiries, and to communicate with you, to enhance the services we offer to our users and to manage and grow our organization. If you register for our newsletters or updates, we may communicate with you by email. To unsubscribe from promotional messages, please follow the instructions within our messages and review the **Control Over Your Information** section below. If you become a contributor, we may also collect your GitHub name and feature you on our website.
- **_Inquiries and Feedback._** If you contact us, we will collect the information that you provide us, such as your contact information and the contents of your communication with us.
You are free to choose which personal information you want to provide to us or whether you want to provide us with personal information at all. However, some information, such as your name, address, payment transaction information, and information on your requested Services may be necessary for the performance of our contractual obligations.
### Information from Third Party Sources
We may receive personal information about you from our business partners and service providers and combine this information with other data we collect from you. The third-parties may include website and service operators, payment processors, marketing partners, and shipping providers. The information may include contact information, demographic information, information about your communications and related activities, and information about your orders. We may use this information to administer and facilitate our services, your orders and our marketing activities.
- **_Single Sign-On._** We use single sign-on ("**SSO**") such as GitHub to allow a user to authenticate their account using one set of login information. We will have access to certain information from those third parties in accordance with the authorization procedures determined by those third parties, including, for example, your name, username, email address, language preference, and profile picture. We use this information to operate, maintain, and provide to you the features and functionality of the Service. We may also send you service-related emails or messages (e.g., account verification, purchase confirmation, customer support, changes or updates to features of the Site, technical and security notices).
- **_Social Media._** When you interact with our Site through various social media, such as when you click on the social media icon on the Site, follow us on a social media site, or post a comment to one of our pages, we may receive information from the social network such as your profile information, profile picture, gender, user name, user ID associated with your social media account, age range, language, country, and any other information you permit the social network to share with third parties. The data we receive is dependent upon your privacy settings with the social network. We use this information to operate, maintain, and provide to you the features and functionality of the Service, as well as to communicate directly with you, such as to send you email messages about products and services that may be of interest to you.
- **_Employment Applications._** If you apply for employment, we collect your contact and demographic information, educational and work history, employment interests, information obtained during interviews and any other information you choose to provide. We use the information provided to evaluate your candidacy for employment, to communicate with you during the application process and to facilitate the onboarding process.
- **_Information from Other Sources._** We may obtain information from other sources, including through third-party information providers, our shareholders, customers, or through transactions such as mergers and acquisitions. We may combine this information with other information we collect from or about you. In these cases, our Privacy Notice governs the handling of the combined personal information. We use this information to operate, maintain, and provide to you the features and functionality of the Service, as well as to communicate directly with you, such as to send you email messages about products and services that may be of interest to you.
### Other Uses of Personal Information
In addition to the uses described above, we may collect and use personal information for the following purposes:
- For our business activities, including to operate the Service and to provide you with the features and functionality of the Service;
- To communicate with you and respond to your requests, such as to respond to your questions, contact you about changes to the Service, and communicate about account related matters;
- For marketing and advertising purposes, such as to market to you or offer you with information and updates on our products or services we think that you may be interested in. While we may use your personal information in this manner, please note that we do not use User Content to serve you ads, and we will never share User Content with any third parties for marketing or advertising purposes, unless you have explicitly submitted it to us for that purpose;
- For analytics and research purposes;
- To enforce our **Terms of Service**, to resolve disputes, to carry out our obligations and enforce our rights, and to protect our business interests and the interests and rights of third parties;
- To comply with contractual and legal obligations and requirements;
- To fulfill any other purpose for which you provide personal information; and
- For any other lawful purpose, or other purpose that you consent to.
## 2. How we share personal information
We may share your personal information in the instances described below. For further information on your choices regarding your information, see **Control Over Your Information**.
- We may share your personal information with third-party service providers or business partners who help us deliver or improve our Site or services, or who perform services on our behalf, which are subject to reasonable confidentiality terms, and may include processing payments, providing web hosting services, or providing analytics.
- Third parties as required by law or subpoena or if we reasonably believe that such action is necessary to (a) comply with the law and the reasonable requests of law enforcement; (b) to enforce our **Terms of Service** or other agreements or to protect the security or integrity of the Supabase services, including to prevent harm or financial loss, or in connection with preventing fraud or illegal activity; and/or (c) to exercise or protect the rights, property, or personal safety of Supabase, our Customers, visitors, or others.
- We may share with other companies and brands owned or controlled by Supabase, and other companies owned by or under common ownership as Supabase. These companies will use your personal information in the same way as we can under this Privacy Notice.
- We may transfer any information we collect in the event we sell or transfer all or a portion of our business or assets (including any shares in the company) or any portion or combination of our products, services, businesses and/or assets. Should such a transaction occur (whether a divestiture, merger, acquisition, bankruptcy, dissolution, reorganization, liquidation, or similar transaction or proceeding), we will use reasonable efforts to ensure that any transferred information is treated in a manner consistent with this Privacy Notice.
- We may disclose your information publicly or with another third party with your prior authorization.
- With others in an aggregated or otherwise anonymized form that does not reasonably identify you directly as an individual.
## 3. Control over your information
### Email Communications
From time to time, we may send you emails regarding updates to our Service, products or services, notices about our organization, or information about products/services we offer (or promotional offers from third parties) that we think may be of interest to you. If you wish to unsubscribe from such emails, simply click the "unsubscribe link" provided at the bottom of the email communication. Note that you cannot unsubscribe from certain services-related email communications (e.g., account verification, confirmations of transactions, technical or legal notices).
### Modifying Account Information
If you have an online account with us, you have the ability to modify certain information in your account (e.g., your contact information) through the account options provided on the Site. If there is personal information in your User Content, you can use the features and functionality of the Service to edit or delete the personal information or User Content. Not all personal information is maintained in a format that you can access or change. If you would like to request access to, or correction or deletion of personal information, you may send your request to us at the email provided below. We will review your request and may require you to provide additional information to identify yourself, but we do not promise that we will be able to satisfy your request.
## 4. How We Use Cookies and Other Tracking Technology to Collect Information
We, and our third-party partners, automatically collect certain types of usage information when you visit our Site, read our emails, or otherwise engage with us.  We typically collect this information through a variety of tracking technologies, including cookies, web beacons, embedded scripts, location-identifying technologies, file information, and similar technology (collectively, "**tracking technologies**").
We, and our third-party partners, use tracking technologies to automatically collect usage and device information, such as:
- Information about your device and its software, such as your IP address, browser type, Internet service provider, device type/model/manufacturer, operating system, date and time stamp, and a unique ID that allows us to uniquely identify your browser or your account (including, for example, a persistent device identifier), and other such information.
- When you access our sites from a mobile device, we may collect unique identification numbers associated with your device or our mobile application mobile carrier, device type, model and manufacturer, mobile device operating system brand and model, and depending on your mobile device settings, we may be able to approximate a device’s location by analyzing other information, like an IP address.
- Information about the way you access and use our services, for example, the site from which you came and the site to which you are going when you leave our services, the pages you visit, the links you click, whether you open emails or click the links contained in emails, whether you access the services from multiple devices, and other actions you take on the Sites.
We use the data collected through tracking technologies to:  (a) remember information so that you will not have to re-enter it during your visit or the next time you visit the site; (b) provide custom content and information; (c) identify you across multiple devices; (d) provide and monitor the effectiveness of our services; (e) monitor aggregate metrics such as total number of visitors, traffic, usage, and demographic patterns on our Site; (f) diagnose or fix technology problems; and (g) to provide, plan for, and enhance our services.
**Note we do not engage in online targeted advertising.**
**Cookies and Other Tracking Technologies Opt-Out.** Depending on your browser or mobile device, you may be able to set your browser to delete or notify you of cookies and other tracking technology by actively managing the settings on your browser or mobile device.
If you would prefer not to accept cookies, most browsers will allow you to: (i) change your browser settings to notify you when you receive a cookie, which lets you choose whether or not to accept it; (ii) disable existing cookies; or (iii) set your browser to automatically reject cookies. Please note that doing so may negatively impact your experience using the sites, as some features and services on our sites may not work properly. Depending on your mobile device and operating system, you may not be able to delete or block all cookies. You may also set your e-mail options to prevent the automatic downloading of images that may contain technologies that would allow us to know whether you have accessed our e-mail and performed certain functions with it.
## 5. Data Retention and Security
We will retain your personal information for the length of time needed to fulfill the purposes outlined in this Privacy Notice, unless a longer retention period is required or permitted by law. We store data on servers in the U.S. or any other country in which Supabase or its affiliates, subsidiaries, agents or contractors maintain facilities. If you are located in the European Union or other regions with laws governing data collection and use that may differ from U.S. law, please note that your personal information may be transferred to a country and jurisdiction that does not have the same data protection laws as your jurisdiction. When you register for use with Supabase you have the option of where you store your information and we will not transfer it without providing information to you in advance.
Supabase cares about the security of your information and uses commercially reasonable physical, technical and organizational measures designed to preserve the integrity and security of all information we collect. However, no security system is impenetrable, and we cannot guarantee the security of our systems 100%. In the event that any information under our control is compromised as a result of a breach of security, we will take reasonable steps to investigate the situation and where appropriate, notify those individuals whose information may have been compromised and take other steps, in accordance with any applicable laws and regulations.
## 6. Links to Third-Party Websites and Services
For your convenience, our Site may provide links to third-party websites or services that we do not own or operate. We are not responsible for the practices employed by any websites or services linked to or from the services, including the information or content contained within them. Your browsing and interaction on any other website or service are subject to the applicable third party’s rules and policies, not ours. If you are using a third-party website or service, you do so at your own risk. We encourage you to review the privacy policies of any site or service before providing any personal information.
## 7. Children’s Privacy
Our services are not intended for children under the age of 13. We do not knowingly solicit or collect personal information from children under the age of 13. If we learn that any personal information has been collected inadvertently from a child under 13, we will delete the information as soon as possible. If you believe that we might have collected information from a child under 13, please contact us at privacy@supabase.io.
## 8. Changes to Privacy Notice
We reserve the right to change this Privacy Notice from time to time in our sole discretion. We will notify you about material changes in the way we treat personal data by sending a notice to the primary email address specified in your Supabase account and/or by placing a prominent notice on our Site. It is your responsibility to review this Privacy Notice periodically. When we do change the Privacy Notice, we will also revise the "last modified" date.
## 9. Contact Us
For additional inquiries about this Privacy Notice, please send us an email at privacy@supabase.io.
This Privacy Notice was last modified on 27th March 2021
## Privacy disclosures for the European economic area, United Kingdom, and Switzerland.
While we are primarily based in the United States, Supabase maintains operations in Europe and may direct our services to individuals located in the European Economic Area ("**_EEA_**"), United Kingdom and Switzerland, including through our Site [supabase.com](/) (collectively, our "**_European Services_**"). The following disclosures ("**_Privacy Disclosures_**") apply to our processing of personal data in connection with our European Services.
Supabase, Inc. is the data controller responsible for the processing of personal data in connection with our European Services. This means that we determine and are responsible for how your personal information is used.
**Personal Data:** When we use the term "personal data" in this section, we mean information relating to an identified or identifiable natural person.
### 1. Personal data we collect from you when you use the Supabase European Services, and how we use it.
We collect the categories of personal data that you voluntarily submit directly to us when you use the European Services, as set forth in our Privacy Notice under the section entitled **Information We Collect and Our Use**. The table at **Annex 1** sets out in detail the categories of personal data we collect about you and how we use that information when you use the European Services, as well as the legal basis which we rely on to process the personal information and recipients of that personal information.
### 2. Information we collect about you automatically.
We also automatically collect personal information indirectly about how you access and use the European Services, and information about the device you use to access the European Services. For example, we may collect:
(a) information about the features you use and the pages you view on the European Services;
(b) information about your device (such as your IP address, device identifier, device type, model and manufacturer); and
(c) information about your usage patterns (such as how often you use the Supabase European Services and your language settings).
We use this information to provide you the features and functionality of the European Services, to monitor and improve the European Services and to develop new services.
The table at **Annex 2** sets out further information about the categories of personal information we collect about you automatically and how we use that information. The table also lists the legal basis which we rely on to process the personal information and recipients of that personal information.
We may link or combine the personal information we collect about you and the information we collect automatically.
We may anonymise and aggregate any of the personal information we collect (so that it does not directly identify you). We may use anonymised information for purposes that include testing our IT systems, research, data analysis, improving the Supabase European Services. We may also share such anonymised and aggregated information with others.
### 3. How long will we store your personal information
We will usually store the personal information we collect about you for no longer than necessary for the purposes set out in Annex 1 and Annex 2, in accordance with our legal obligations and legitimate business interests.
The criteria used to determine the period for which personal information about you will be retained varies depending on the legal basis under which we process the personal information:
1. **Legitimate Interests.** Where we are processing personal information based on our legitimate interests, we generally will retain such information for a reasonable period of time based on the particular interest, taking into account the fundamental interests and the rights and freedoms of data subjects.
2. **Consent.** Where we are processing personal information based on your consent, we generally will retain the information until you withdraw your consent, or otherwise for the period of time necessary to fulfill the underlying agreement with you or provide you with the applicable service for which we process that personal information.
3. **Contract.** Where we are processing personal information based on contract, we generally will retain the information for the duration of the contract plus some additional limited period of time that is necessary to comply with law or that represents the statute of limitations for legal claims that could arise from the contractual relationship.
4. **Legal Obligation.** Where we are processing personal information based on a legal obligation, we generally will retain the information for the period of time necessary to fulfill the legal obligation.
5. **Legal Claim.** We may need to apply a "legal hold" that retains information beyond our typical retention period where we face threat of legal claim.  In that case, we will retain the information until the hold is removed, which typically means the claim or threat of claim has been resolved.
In all cases, in addition to the purposes and legal bases, we consider the amount, nature and sensitivity of the personal information, as well as the potential risk of harm from unauthorized use or disclosure of your personal information.
### 4. Recipients of Personal Information
In addition to the recipients listed in Annexes 1 and 2, we may also share your personal information with the following (as required in accordance with the uses set out in Annexes 1 and 2):
1. **Service providers and advisors**: we may share your personal information with third party vendors and other service providers that perform services for us or on our behalf, which may include providing professional services, such as legal and accounting services, mailing, email or chat services, fraud prevention, web hosting, or providing analytic services.
2. **Affiliates**. Other companies owned by or under common ownership as Supabase, including our subsidiaries (i.e., any organization we own or control) and our ultimate holding company (i.e., any organization that owns or controls us) and any subsidiaries it owns. These companies will use your personal information in the same way as we can under these Privacy Disclosures.
3. **Purchasers and third parties in connection with a business transaction**: your personal information may be disclosed to third parties in connection with a transaction, such as a merger, sale of assets or shares, reorganization, financing, change of control or acquisition of all or a portion of our business.
4. **Law enforcement, regulators and other parties for legal reasons**: we may share your personal information with third parties as required by law or if we reasonably believe that such action is necessary to (i) comply with the law and the reasonable requests of law enforcement; (ii) detect and investigate illegal activities and breaches of agreements, including our Terms; and/or (iii) exercise or protect the rights, property, or personal safety of Supabase, its users or others.
### 5. Marketing and Advertising
From time to time we may contact you with information about our services, including sending you marketing messages and asking for your feedback on our services. Most marketing messages we send will be by email. For some marketing messages, we may use personal information we collect about you to help us determine the most relevant marketing information to share with you.
We will only send you marketing messages if you have given us your consent to do so. You can withdraw your consent at a later date by clicking on the unsubscribe link at the bottom of our marketing emails or by updating your preferences via your account on the Site.
### 6. Storing and transferring your personal information
**Security**. We implement appropriate technical and organizational measures to protect your personal information against accidental or unlawful destruction, loss, change or damage. All personal information we collect will be stored by our cloud hosting provider on secure servers. We will never send you unsolicited emails or contact you by phone requesting credit or debit card information or national identification numbers.
**International Transfers of your Personal Information**. The personal information we collect may be transferred to and stored in countries outside of the jurisdiction you are in where we and our third party service providers have operations. If you are located in the EEA, United Kingdom or Switzerland, your personal information may be processed outside of those regions, including in the United States.
In the event of such a transfer, we ensure that: (i) the personal information is transferred to countries recognized as offering an equivalent level of protection; or (ii) the transfer is made pursuant to appropriate safeguards, such as standard data protection clauses adopted by the European Commission.
If you wish to enquire further about these safeguards used, please contact us using the details set out at the end of these Privacy Disclosures.
### 7. Profiling
We may analyze personal data we have collected about you to create a profile of your interests and send product updates. We may also use personal data about you to detect and reduce fraud.
### 8. Your rights in respect of your personal information
In accordance with applicable privacy law, you have the following rights in respect of your personal information that we hold:
1. **Right of access**. You have the right to obtain:
1. confirmation of whether, and where, we are processing your personal information;
2. information about the categories of personal information we are processing, the purposes for which we process your personal information and information as to how we determine applicable retention periods;
3. information about the categories of recipients with whom we may share your personal information; and
4. a copy of the personal information we hold about you.
2. **Right of portability**. You have the right, in certain circumstances, to receive a copy of the personal information you have provided to us in a structured, commonly used, machine-readable format that supports re-use, or to request the transfer of your personal data to another person.
3. **Right to rectification**. You have the right to obtain rectification of any inaccurate or incomplete personal information we hold about you without undue delay.
4. **Right to erasure**. You have the right, in some circumstances, to require us to erase your personal information without undue delay if the continued processing of that personal information is not justified.
5. **Right to restriction**. You have the right, in some circumstances, to require us to limit the purposes for which we process your personal information if the continued processing of the personal information in this way is not justified, such as where the accuracy of the personal information is contested by you.
6. **Right to withdraw consent**. There are certain circumstances where we require your consent to process your personal information. In these instances, and if you have provided consent, you have the right to withdraw your consent. If you withdraw your consent, this will not affect the lawfulness of our use of your personal information before your withdrawal.
**You also have the right to object to any processing based on our legitimate interests where there are grounds relating to your particular situation. There may be compelling reasons for continuing to process your personal information, and we will assess and inform you if that is the case. You can object to marketing activities for any reason.**
You also have the right to lodge a complaint to your local data protection authority. If you are based in the European Union, information about how to contact your local data protection authority is available [here](http://ec.europa.eu/justice/data-protection/bodies/authorities/index_en.htm). If you are based in the UK or Switzerland, your local data protection authorities are the UK Information Commissioner's Office (<https://ico.org.uk/global/contact-us/>) and the Swiss Federal Data Protection and Information Commissioner (<https://www.edoeb.admin.ch/edoeb/en/home/the-fdpic/contact/address.html>).
If you wish to exercise one of these rights, please contact us using the contact details at the end of these Privacy Disclosures.
Due to the confidential nature of data processing we may ask you to provide proof of identity when exercising the above rights. This can be done by providing a scanned copy of a valid identity document or a signed photocopy of a valid identity document.
### 9. Cookies and similar technologies used on our European Services
Our European Services uses cookies and similar technologies such as pixels and Local Storage Objects (LSOs) like HTML5 (together "**_cookies_**") to distinguish you from other users of our European Services. This helps us to provide you with a good experience when you browse our European Services and also allows us to monitor and analyse how you use and interact with our European Services so that we can continue to improve our European Services.
Cookies are pieces of code that allow for personalization of our European Services experience by saving your information such as user ID and other preferences. A cookie is a small data file that we transfer to your computer's hard disk for record-keeping purposes.
We use the following types of cookies:
1. **Strictly necessary cookies**. These are cookies that are required for the operation of our European Services. They include, for example, cookies that enable you to log into secure areas of our European Services.
Please see **Annex 3** for more information about the cookies we use on the European Services.
Most browsers also allow you to change your cookie settings to block certain cookies. Depending on your mobile device and operating system, you may not be able to delete or block all cookies. Please note that if you choose to refuse all cookies you may not be able to use the full functionality of our European Services. These settings will typically be found in the "options" or "preferences" menu of your browser. In order to understand these settings, the following links may be helpful, otherwise you should use the "Help" option in your browser for more details.
- [Cookie settings in Internet Explorer](https://support.microsoft.com/en-gb/help/278835/how-to-delete-cookie-files-in-internet-explorer)
- [Cookie settings in Firefox](http://support.mozilla.org/en-US/kb/cookies)
- [Cookie settings in Chrome](https://support.google.com/chrome/answer/95647?hl=en)
- [Cookies settings in Safari web](https://support.apple.com/en-gb/guide/safari/manage-cookies-and-website-data-sfri11471/mac) and [iOS](https://support.apple.com/en-gb/HT201265).
If you would like to find out more about cookies and other similar technologies, please visit [allaboutcookies.org](http://www.allaboutcookies.org).
Please note that deleting or blocking cookies may not be effective for all types of tracking technologies, such as Local Storage Objects (LSOs) like HTML5.
### 10. Tracking technologies used in our emails
Our emails may contain tracking pixels that identify if and when you have opened an email that we have sent you, how many times you have read it and whether you have clicked on any links in that email. This helps us measure the effectiveness of our marketing email campaigns, make the emails we send to you more relevant to your interests and to understand if you have opened and read any important administrative emails we might send you.
Most popular email clients will allow you to block these pixels by disabling certain external images in emails. You can do this through the settings on your email client – these generally give you the option of choosing whether emails will display "remote images", "remote content" or "images" by default.
Some browsers also give you the option of downloading and installing extensions that block pixels and other tracking technologies.
## Annex 1 – Personal information you provide to us
| **Category of Personal Information** | **How we may use the Personal Information** | **Legal Bases for Processing** | **Recipients of Personal Information** |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Contact information**, such as first name, last name and email address. | We may use this information to set up and authenticate your account on the Service. | The processing is necessary for the performance of a contract with you and to take steps prior to entering into a contract with you, namely our Terms of Service. | <p>We may share this information with the following service providers through the provision of the Service: Segment, Auth0, Stripe, Intercom, Hubspot, Mixpanel, Notion, Slack, Amazon Web Services, and BigQuery (Google Cloud). </p><p> </p> |
| | We may use this information to communicate with you, including sending service-related communications. | The processing is necessary for the performance of a contract with you, namely our Terms of Service. | |
| | We may use this information to deal with enquiries and complaints made by or about you relating to the Service. | The processing is necessary for our legitimate interests, namely administering the Service, and for communicating with you effectively to respond to your queries or complaints. | |
| | We may use this information in connection with providing you with marketing communications in accordance with your preferences. | We will only use your personal information in this way to the extent you have given us consent to do so. | |
| **Your registration / account information** such as your full name, email, and password. | <p>We may use this information to create your account on the Service.</p><p></p><p></p> | <p>The processing is necessary for the performance of a contract with you.</p><p></p><p></p> | <p>We may share this information with the following service providers through the provision of the Service: Segment, Auth0, Stripe, Amazon Web Services.</p><p></p> |
| | <p>We use this information to deal with enquiries and complaints made by or about you relating to the Service.</p><p></p> | The processing is necessary for our legitimate interests, namely for communicating with our members effectively to respond to any queries or complaints. | |
| **Payment transaction information.** When you make a purchase, we may collect information such as your billing address and other information such as date and time of your transaction. | <p>We may use this information to process your orders through the Service.</p><p></p> | The processing is necessary for the performance of a contract. | <p>We may share this information with the following service providers through the provision of the Service: Stripe, and Amazon Web Services.</p><p></p> |
| | We may use this information to verify your identity in connection with the detection and prevention of fraud or financial crime. | The processing is necessary for our and third partiers' legitimate interests, namely the detection and prevention of fraud and financial crime. | |
| **Approximate Location information.** When you visit our Service, we may collect information about your location. This information may be derived from WiFi positioning or your IP address. | We may use information to present the Service to you on your device. | The processing is necessary for performance of a contract with you. | <p>We may share this information with the following service providers through the provision of the Service: Sentry, BigQuery (Google Cloud), and Amazon Web Services.</p><p></p> |
| | We may use this information to localise features of the Service. | The processing is necessary for our legitimate interest, namely localising features of the Service and tailoring the Service so that it is more relevant to our users. | |
| | We may use this information to determine content that may be of interest to you. | The processing is necessary for our legitimate interests, namely tailoring the Service so that it is more relevant to you. | |
| **Chat, comments and opinions.** When you contact us directly, e.g. by email or phone we will record your comments and opinions. | We may use this information to address your questions, issues and concerns. | The processing is necessary for our legitimate interests, namely communicating with you and responding to queries, complaints and concerns. | <p>We may share this information with the following service providers through the provision of the Service: Intercom, Hubspot, Google Gsuite, and Slack.</p><p></p> |
| | We may use this information to improve the Service. | The processing is necessary for our legitimate interests (to develop and improve our service). | |
| **Information received from third parties, such as social networks.** If you interact with us through a social network, we may receive information from the social network such as your name, profile information, and any other information you permit the social network to share with third parties. We use single sign-on ("**_SSO_**") such as GitHub to allow a user to authenticate their account using one set of login information. The data we receive is dependent on your privacy settings with the social network. | We may use this information to reshare content created through the use of the Service | The processing is necessary for our legitimate interests (to develop our service and inform our marketing strategy) | We may share this information with the following service providers through the provision of the Service: Auth0 and Slack. |
| | <p>We may use this information to authenticate you and allow you to access the Service.</p><p></p> | The processing is necessary for the performance of a contract with you. | |
| **Your preferences**, such as preferences set for notifications, marketing communications, how the Service is displayed and the active functionalities on the Service. | <p>We use this information to provide notifications, send news, alerts and marketing communications and provide the Service in accordance with your choices.</p><p></p> | <p>The processing is necessary for our legitimate interest, namely ensuring the user receives the correct marketing and other communications, and that this is displayed in accordance with the user's preferences.</p><p></p> | We may share this information with the following service providers through the provision of the Service: Segment, Intercom and Hubspot. |
| | <p>We use this information to ensure that we comply with our legal obligation to send only those marketing communications to which you have consented. </p><p></p> | The processing is necessary for compliance with a legal obligation to which we are subject. | |
## Annex 2 – Personal information collected automatically
| **Category of personal information** | **How we may use it** | **Legal basis for the processing** | **Recipients of Personal Data** |
| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Approximate location information.** Other than information you choose to provide to us, we do not collect information about your precise location. Your device’s IP address may however help us determine an approximate location. | We may use information you provide to us about your location to monitor and detect fraud or suspicious activity in relation to your Supabase account. | The processing is necessary for our legitimate interests, namely to protect our business and your account from fraud and other illegal activities. | <p>**Approximate location information:** We may share this information with the following service providers through the provision of the Service: Sentry, BigQuery (Google Cloud), and Amazon Web Services.</p><p></p><p></p><p></p><p>**Information about how you access and use the Service.** We may share this information with the following service providers through the provision of the Service: Segment, Mixpanel, Intercom, Hubspot, BigQuery (Google Cloud), and Amazon Web Services.</p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p>**Log files and information about your device.** We may share this information with the following service providers through the provision of the Service: Segment, Mixpanel, Intercom, Hubspot, Sentry, BigQuery (Google Cloud), and Amazon Web Services.</p> |
| | We may use this information to tailor how the Service is displayed to you (such as the language in which it is provided to you). | The processing is necessary for our legitimate interest, namely tailoring our service so that it is more relevant to our users. | |
| **Information about how you access and use the Service.** For example, how frequently you access the Service, the time you access the Service and how long you use it for, the approximate location that you access the Service from, the site from which you came and the site to which you are going when you leave our website, the website pages you visit, the links you click, whether you open emails or click the links contained in emails, whether you access the Service from multiple devices, and other actions you take on the Service. | <p>We may use information about how you use and connect to the Service to present the Service to you on your device.</p><p></p> | The processing is necessary for our legitimate interests, namely to tailor the Service to the user. | |
| | We may use this information to determine products and services that may be of interest to you for marketing purposes. | The processing is necessary for our legitimate interests, namely to inform our direct marketing. | |
| | <p>We may use this information to monitor and improve the Service and business, resolve issues and to inform the development of new products and services.</p><p></p> | The processing is necessary for our legitimate interests, namely to monitor and resolve issues with the Service and to improve the Service generally. | |
| **Log files and information about your device.** We also collect information about the tablet, smartphone or other electronic device you use to connect to the Service. This information can include details about the, operating systems, browsers and applications connected to the Service through the device and your IP address. | <p>We may use information about how you use and connect to the Service to present the Service to you on your device.</p><p></p> | The processing is necessary for our legitimate interests, namely to tailor the Service to the user. | |
| | <p>We may use this information to monitor and improve the Service and business, resolve issues and to inform the development of new products and services.</p><p></p> | The processing is necessary for our legitimate interests, namely to monitor and resolve issues with the Service and to improve the Service generally. | |
## Annex 3 - Cookies
| **Cookie Name** | **Type of cookie** | **How long does the cookie stay on my device?** | **Purpose of the cookie** |
| :----------------------------- | :----------------- | :---------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| <p>a0:session</p><p></p> | Strictly necessary | 1 Day | Authentication Purposes. |
| <p>a0:state</p><p></p> | Strictly necessary | 2 Hours | Authentication Purposes. |
| <p>youtube-nocookie</p><p></p> | Strictly necessary | Persistent | <p>Privacy-enhanced cookie, essential for embedded videos. [Link.](https://support.google.com/youtube/answer/171780)</p><p><blockquote><small>Privacy Enhanced Mode allows you to embed YouTube videos without using cookies that track viewing behavior. This means no activity is collected to personalize the viewing experience.</small></blockquote></p> |
-88
View File
@@ -1,88 +0,0 @@
---
id: sla
title: Service Level Agreement
---
The following Service Level Agreement, which is incorporated into and forms part of the Subscription Agreement between Supabase, Inc. ("Supabase") and Customer (the "Agreement"), will apply to the Services for Enterprise Customers specified in an Order Form during the applicable Subscription Term:
## Platform
### 1. Uptime Commitment
Supabase will provide Actual Availability for at least ninety-nine and nine tenths percent (99.9%) of the total time in each calendar month during the Subscription Term, as measured by Supabase (the **"Uptime Commitment"**).
### 2. Service Credits
If the Uptime Commitment is not met during any particular calendar month during the Subscription Term, then Customer will be eligible for a service credit ("Service Credit"), provided that Customer reports to Supabase such failure to meet the Uptime Commitment and requests such Service Credit in accordance with this Exhibit. The amount of any Service Credit due hereunder shall be calculated as follows:
X \* Y, where X = the total fees due from Customer to Supabase for the affected Services for the relevant calendar month (regardless of when billed or payable), and Y = the Credit Percentage corresponding with the Actual Availability provided (as a percentage of total time) for the relevant calendar month, as set forth in the table below.
| Actual Availability | Credit Percentage |
| -------------------------------------------------- | ----------------- |
| Less than 99.9% but greater than or equal to 99.0% | 10% |
| Less than 99.0% but greater than or equal to 98.0% | 15% |
| Less than 98.0% but greater than or equal to 96.0% | 20% |
| Less than 96.0% | 30% |
### 3. Credit Requests and Payment
To request a Service Credit, Customer must send an email to Supabase at support@supabase.io within thirty (30) days of the end of the month in which the Uptime Commitment was not met. Customer must include either its account ID or registered email address, and the previously reported dates and times that there was no Service Availability. If Supabase confirms that Customer is eligible for a Service Credit, Supabase will issue a credit to Customer’s account within thirty (30) days. Service Credits are not refunds, cannot be exchanged into a cash amount, and may only be used against future billing charges. Except as set forth in Section 4 below, the Service Credits shall be Customer’s sole and exclusive remedy, and Supabase’s sole and exclusive liability, for any failure by Supabase to meet the Uptime Commitment.
### 4. Definitions
All capitalized words used but not defined in this Service Level Agreement have the meaning set forth in the Agreement.
#### 4.1 Scheduled Availability
"Scheduled Availability" means the time, in minutes, that the applicable Services are generally accessible and available to Customer’s Permitted Users.
#### 4.2 Unscheduled Downtime
"Unscheduled Downtime" means the time, in minutes, that the applicable Services are not generally accessible and available to Customer’s Permitted Users, excluding inaccessibility or unavailability due to Customer’s or Permitted Users’ acts or omissions, force majeure events, scheduled maintenance disclosed with at least 24 hours’ notice by email, hacking or virus attacks, or reasonable emergency maintenance.
#### 4.3 Actual Availability
"Actual Availability" means Scheduled Availability less Unscheduled Downtime.
## Support
Supabase Support Service Level Agreements.
### 1. Urgent
**Critical Issue**
Defect resulting in full or partial system outage or a condition that makes Supabase unusable
or unavailable in production for all of Customer’s Users.
### 2. High
**Significant Business Disruption**
Issue resulting in a situation meaning major functionality is impacted and
significant performance degradation is experienced. Issue impacts significant proportion of user base and / or major
Supabase functionality.
### 3. Normal
**Minor Feature or Functional Issue / General Question**
Issue results in a component of Supabase not
performing as expected or documented. An inquiry by a Customer representative regarding a general technical issue
or general question.
### 4. Low
**Minor Issue / Feature Request**
An Information request about Supabase or feature request.
## Target response times
| Severity Level | Standard | Priority | Priority Plus |
| -------------- | ------------------------------------- | ------------------------------------- | -------------------------------------- |
| 1. Urgent | 1 business hour<br />24/7 × 365 | 1 business hour<br />24/7 × 365 | 1 business hour<br />24/7 × 365 |
| 2. High | 4 business hours<br />Monday - Friday | 2 business hours<br />Monday - Friday | 2 business hours<br />24/7 × 365 |
| 3. Normal | 1 business day<br />Monday - Friday | 1 business day<br />Monday - Friday | 12 business hours<br />Monday - Friday |
| 4. Low | 2 business days<br />Monday - Friday | 2 business days<br />Monday - Friday | 1 business day<br />Monday - Friday |
Business hours are from 6am to 6pm (local time), except where otherwise stated.
-235
View File
@@ -1,235 +0,0 @@
---
id: terms
title: Terms of Service
---
`Last Modified: 20 November 2020`
These Customer Terms and Conditions (this "**Agreement**"), effective as of the date on which you click a button or check a box (or something similar) acknowledging your acceptance of this Agreement (the "**Effective Date**"), is by and between Supabase, Inc., a Delaware corporation with offices located at 970 Toa Payoh North #07-04, Singapore 318992 ("**Supabase**") and the entity on whose behalf the individual accepting this Agreement accepts this Agreement ("**Customer**"). The individual accepting this Agreement hereby represents and warrants that it is duly authorized by the entity on whose behalf it accepts this Agreement to so accept this Agreement. Supabase and Customer may be referred to herein collectively as the "**Parties**" or individually as a "**Party**." The Parties agree as follows:
## 1. Definitions.
1. "**Aggregated Data**" means data and information related to or derived from Customer Data or Customer's use of the Services that is used by Supabase in an aggregate and anonymized manner, including to compile statistical and performance information related to the Services.
2. "**Authorized User**" means Customer's employees, consultants, contractors, and agents (i) who are authorized by Customer to access and use the Services under the rights granted to Customer pursuant to this Agreement; and (ii) for whom access to the Services has been purchased hereunder.
3. "**Customer Data**" means information, data, and other content, in any form or medium, that is submitted, posted, or otherwise transmitted by or on behalf of Customer or an Authorized User through the Services; provided that, for purposes of clarity, Customer Data does not include Aggregated Data.
4. "**Documentation**" means Supabase's end user documentation relating to the Services available at [supabase.io](https://supabase.com).
5. "**Harmful Code**" means any software, hardware, or other technology, device, or means, including any virus, worm, malware, or other malicious computer code, the purpose or effect of which is to permit unauthorized access to, or to destroy, disrupt, disable, distort, or otherwise harm or impede in any manner any (i) computer, software, firmware, hardware, system, or network; or (ii) any application or function of any of the foregoing or the security, integrity, confidentiality, or use of any data processed thereby.
6. "**Order**" means: (i) the purchase order, order form, or other ordering document entered into by the Parties that incorporates this Agreement by reference; or (ii) if Customer registered for the Services through Supabase's online ordering process, the results of such online ordering process.
7. "**Personal Information**" means any information that, individually or in combination, does or can identify a specific individual or by or from which a specific individual may be identified, contacted, or located, including without limitation all data considered "personal data", "personally identifiable information", or something similar under applicable laws, rules, or regulations relating to data privacy.
8. "**Supabase IP**" means the Services, the Documentation, and any and all intellectual property provided to Customer or any Authorized User in connection with the foregoing. For the avoidance of doubt, Supabase IP includes Aggregated Data and any information, data, or other content derived from Supabase's provision of the Services but does not include Customer Data.
9. "**Services**" means Supabase's proprietary hosted software platform, as made available by Supabase to Authorized Users from time to time.
10. "**Subscription Period**" means the time period identified on the Order during which Customer's Authorized Users may access and use the Services.
11. "**Third-Party Products**" means any third-party products provided with, integrated with, or incorporated into the Services.
12. "**Usage Limitations**" means the usage limitations set forth in this Agreement and the Order, including without limitation any limitations on the number of Authorized Users (if any), and the applicable product, pricing, and support tiers agreed-upon by the Parties.
## 2. Access and Use.
### 1. Provision of Access.
Subject to and conditioned on Customer's compliance with the terms and conditions of this Agreement, including without limitation the Usage Limitations, Supabase will make available to Customer during the Subscription Period, on a non-exclusive, non-transferable (except in compliance with Section 13.8), and non-sublicensable basis, access to and use of the Services, solely for use by Authorized Users. Such use is limited to Customer's internal business purposes and the features and functionalities specified in the Order. Supabase shall provide to Customer the necessary access credentials to allow Customer to access the Services.
### 2. Documentation License.
Subject to and conditioned on Customer's compliance with the terms and conditions of this Agreement, Supabase hereby grants to Customer a non-exclusive, non-transferable (except in compliance with Section 13.8), and non-sublicensable license to use the Documentation during the Subscription Period solely for Customer's internal business purposes in connection with its use of the Services.
### 3. Use Restrictions.
Customer shall not use the Services for any purposes beyond the scope of the access granted in this Agreement. Customer shall not at any time, directly or indirectly, and shall not permit any Authorized Users to: (i) copy, modify, or create derivative works of any Supabase IP, whether in whole or in part; (ii) rent, lease, lend, sell, license, sublicense, assign, distribute, publish, transfer, or otherwise make available the Services or Documentation to any third party; (iii) reverse engineer, disassemble, decompile, decode, adapt, or otherwise attempt to derive or gain access to any software component of the Services, in whole or in part; (iv) remove any proprietary notices from any Supabase IP; (v) use any Supabase IP in any manner or for any purpose that infringes, misappropriates, or otherwise violates any intellectual property right or other right of any person, or that violates any applicable law; (vi) access or use any Supabase IP for purposes of competitive analysis of Supabase or the Services, the development, provision, or use of a competing software service or product, or any other purpose that is to Supabase's detriment or commercial disadvantage; (vii) bypass or breach any security device or protection used by the Services or access or use the Services other than by an Authorized User through the use of valid access credentials; or (vii) input, upload, transmit, or otherwise provide to or through the Services any information or materials that are unlawful or injurious, or that contain, transmit, or activate any Harmful Code.
### 4. Reservation of Rights.
Supabase reserves all rights not expressly granted to Customer in this Agreement. Except for the limited rights and licenses expressly granted under this Agreement, nothing in this Agreement grants, by implication, waiver, estoppel, or otherwise, to Customer or any third party any intellectual property rights or other right, title, or interest in or to the Supabase IP.
### 5. Suspension.
Notwithstanding anything to the contrary in this Agreement, Supabase may temporarily suspend Customer's and any Authorized User's access to any portion or all of the Services if: (i) Supabase reasonably determines that (A) there is a threat or attack on any of the Supabase IP; (B) Customer's or any Authorized User's use of the Supabase IP disrupts or poses a security risk to the Supabase IP or to any other customer or vendor of Supabase; (C) Customer, or any Authorized User, is using the Supabase IP for fraudulent or illegal activities; (D) subject to applicable law, Customer has ceased to continue its business in the ordinary course, made an assignment for the benefit of creditors or similar disposition of its assets, or become the subject of any bankruptcy, reorganization, liquidation, dissolution, or similar proceeding; or (E) Supabase's provision of the Services to Customer or any Authorized User is prohibited by applicable law; (ii) any vendor of Supabase has suspended or terminated Supabase's access to or use of any Third-Party Products required to enable Customer to access the Services; or (iii) in accordance with Section 5.1 (any such suspension described in subclause (i), (ii), or (iii), a "**Service Suspension**"). Supabase shall use commercially reasonable efforts to provide written notice of any Service Suspension to Customer and to provide updates regarding resumption of access to the Services following any Service Suspension. Supabase shall use commercially reasonable efforts to resume providing access to the Services as soon as reasonably possible after the event giving rise to the Service Suspension is cured. Supabase will have no liability for any damage, liabilities, losses (including any loss of data or profits), or any other consequences that Customer or any Authorized User may incur as a result of a Service Suspension.
### 6. Aggregated Data.
Notwithstanding anything to the contrary in this Agreement, Supabase may monitor Customer's use of the Services and collect and compile Aggregated Data. As between Supabase and Customer, all right, title, and interest in Aggregated Data, and all intellectual property rights therein, belong to and are retained solely by Supabase. Customer acknowledges that Supabase may compile Aggregated Data based on Customer Data input into the Services. Customer agrees that Supabase may (i) make Aggregated Data available to third parties including its other customers in compliance with applicable law, and (ii) use Aggregated Data to the extent and in the manner permitted under applicable law.
## 3. Customer Responsibilities.
### 1. General.
Customer is responsible and liable for all uses of the Services and Documentation resulting from access provided by Customer, directly or indirectly, whether such access or use is permitted by or in violation of this Agreement. Without limiting the generality of the foregoing, Customer is responsible for all acts and omissions of Authorized Users, and any act or omission by an Authorized User that would constitute a breach of this Agreement if taken by Customer will be deemed a breach of this Agreement by Customer. Customer shall use reasonable efforts to make all Authorized Users aware of this Agreement's provisions as applicable to such Authorized User's use of the Services and shall cause Authorized Users to comply with such provisions.
### 2. Third-Party Products.
Supabase may from time to time make Third-Party Products available to Customer or Supabase may allow for certain Third-Party Products to be integrated with the Services to allow for the transmission of Customer Data from such Third-Party Products into the Services. For purposes of this Agreement, such Third-Party Products are subject to their own terms and conditions. If Customer does not agree to abide by the applicable terms for any such Third-Party Products, then Customer should not install or use such Third-Party Products. By authorizing Supabase to transmit Customer Data from Third-Party Products into the Services, Customer represents and warrants to Supabase that it has all right, power, and authority to provide such authorization.
### 3. Customer Control and Responsibility.
Customer has and will retain sole responsibility for: (i) all Customer Data, including its content and use; (ii) all information, instructions, and materials provided by or on behalf of Customer or any Authorized User in connection with the Services; (iii) Customer's information technology infrastructure, including computers, software, databases, electronic systems (including database management systems), and networks, whether operated directly by Customer or through the use of third-party services ("**Customer Systems**"); (iv) the security and use of Customer's and its Authorized Users' access credentials; and (v) all access to and use of the Services directly or indirectly by or through the Customer Systems or its or its Authorized Users' access credentials, with or without Customer's knowledge or consent, including all results obtained from, and all conclusions, decisions, and actions based on, such access or use.
## 4. Support.
During the Subscription Period, Supabase will use commercially reasonable efforts to provide Customer with basic customer support via Supabase's standard support channels during Supabase's normal business hours.
## 5. Fees and Taxes.
### 1. Fees.
Where paid for services are agreed between Supabase and Customer per the Order, Customer shall pay Supabase the fees ("**Fees**") identified in the Order without offset or deduction at the cadence identified in the Order (e.g., monthly or annually). Fees paid by Customer are non-refundable. If Customer fails to make any payment when due, and Customer has not notified Supabase in writing within ten (10) days of the payment becoming due and payable that the payment is subject to a good faith dispute, without limiting Supabase's other rights and remedies: (i) Supabase may charge interest on the undisputed past due amount at the rate of 1.5% per month, calculated daily and compounded monthly or, if lower, the highest rate permitted under applicable law; (ii) Customer shall reimburse Supabase for all reasonable costs incurred by Supabase in collecting any late payments or interest, including attorneys' fees, court costs, and collection agency fees; and (iii) if such failure continues for ten (10) days or more, Supabase may suspend Customer's and its Authorized Users' access to any portion or all of the Services until such amounts are paid in full.
### 2. Taxes.
All Fees and other amounts payable by Customer under this Agreement are exclusive of taxes and similar assessments. Customer is responsible for all sales, use, and excise taxes, and any other similar taxes, duties, and charges of any kind imposed by any federal, state, or local governmental or regulatory authority on any amounts payable by Customer hereunder, other than any taxes imposed on Supabase's income. To the extent that Supabase is required by law to pay any such taxes, duties, or other charges to any governmental or regulatory authority, Supabase may invoice Customer for such taxes, duties, or other charges and Customer will pay such invoiced amounts in accordance with this Agreement.
## 6. Confidential Information.
### 1. Definition.
From time to time during the Subscription Period, either Party may disclose or make available to the other Party information about its business affairs, products, confidential intellectual property, trade secrets, third-party confidential information, and other sensitive or proprietary information, whether orally or in written, electronic, or other form or media that: (i) is marked, designated or otherwise identified as "confidential" or something similar at the time of disclosure or within a reasonable period of time thereafter; or (ii) would be considered confidential by a reasonable person given the nature of the information or the circumstances of its disclosure (collectively, "**Confidential Information**"). Except for Personal Information, Confidential Information does not include information that, at the time of disclosure is: (a) in the public domain; (b) known to the receiving Party at the time of disclosure; (c) rightfully obtained by the receiving Party on a non-confidential basis from a third party; or (d) independently developed by the receiving Party without use of, reference to, or reliance upon the disclosing Party's Confidential Information.
### 2. Duty.
The receiving Party shall not disclose the disclosing Party's Confidential Information to any person or entity, except to the receiving Party's employees, contractors, and agents who have a need to know the Confidential Information for the receiving Party to exercise its rights or perform its obligations hereunder ("**Representatives**"). The receiving Party will be responsible for all the acts and omissions of its Representatives as they relate to Confidential Information hereunder. Notwithstanding the foregoing, each Party may disclose Confidential Information to the limited extent required (i) in order to comply with the order of a court or other governmental body, or as otherwise necessary to comply with applicable law, provided that the Party making the disclosure pursuant to the order shall first have given written notice to the other Party and made a reasonable effort to obtain a protective order; or (ii) to establish a Party's rights under this Agreement, including to make required court filings. Further, notwithstanding the foregoing, each Party may disclose the terms and existence of this Agreement to its actual or potential investors, debtholders, acquirers, or merger partners under customary confidentiality terms.
### 3. Return of Materials; Effects of Termination/Expiration.
On the expiration or termination of the Agreement, the receiving Party shall promptly return to the disclosing Party all copies, whether in written, electronic, or other form or media, of the disclosing Party's Confidential Information, or destroy all such copies and certify in writing to the disclosing Party that such Confidential Information has been destroyed. Each Party's obligations of non-use and non-disclosure with regard to Confidential Information are effective as of the Effective Date and will expire three (3) years from the date of termination or expiration of this Agreement; provided, however, with respect to any Confidential Information that constitutes a trade secret (as determined under applicable law), such obligations of non-disclosure will survive the termination or expiration of this Agreement for as long as such Confidential Information remains subject to trade secret protection under applicable law.
## 7. Personal Information.
Customer will ensure that its Customer Data, and its use of such Customer Data, complies with this Agreement and any applicable law. Customer is responsible for properly configuring and using the Services and taking its own steps to maintain appropriate security, protection, and backup of Customer Data. Customer may not store or process protected health information (as defined in HIPAA) using the Services unless Customer signs a Business Associate Agreement with Supabase. Customer may not store any payment cardholder information using the Services without Supabase's prior written approval.
## 8. Intellectual Property Ownership; Feedback.
### 1. Supabase IP.
Customer acknowledges that, as between Customer and Supabase, Supabase owns all right, title, and interest, including all intellectual property rights, in and to the Supabase IP and, with respect to Third-Party Products, the applicable third-party providers own all right, title, and interest, including all intellectual property rights, in and to the Third-Party Products.
### 2. Customer Data.
Supabase acknowledges that, as between Supabase and Customer, Customer owns all right, title, and interest, including all intellectual property rights, in and to the Customer Data. Customer hereby grants to Supabase a non-exclusive, royalty-free, worldwide license to reproduce, distribute, and otherwise use and display the Customer Data and perform all acts with respect to the Customer Data as may be necessary for Supabase to provide the Services to Customer, and a non-exclusive, perpetual, irrevocable, royalty-free, worldwide license to reproduce, distribute, modify, and otherwise use and display Customer Data incorporated within the Aggregated Data. Customer may export the Customer Data at any time through the features and functionalities made available via the Services.
### 3. Feedback.
If Customer or any of its employees or contractors sends or transmits any communications or materials to Supabase by mail, email, telephone, or otherwise, suggesting or recommending changes to the Supabase IP, including without limitation, new features or functionality relating thereto, or any comments, questions, suggestions, or the like ("**Feedback**"), Supabase is free to use such Feedback irrespective of any other obligation or limitation between the Parties governing such Feedback so long as Supabase does not identify Customer as the source of the Feedback without Customer's prior approval.
## 9. Warranty Disclaimer.
The Supabase IP is provided "as is" and Supabase
hereby disclaims all warranties, whether express, implied, statutory, or
otherwise. Supabase specifically disclaims all implied warranties of
merchantability, fitness for a particular purpose, title, and non-infringement,
and all warranties arising from course of dealing, usage, or trade practice. Supabase
makes no warranty of any kind that the Supabase IP, or any products or results
of the use thereof, will meet Customer’s or any other person’s requirements,
operate without interruption, achieve any intended result, be compatible or
work with any software, system or other services, or be secure, accurate,
complete, free of harmful code, or error free.
## 10. Indemnification.
### 1. Supabase Indemnification.
1. Supabase shall indemnify, defend, and hold harmless Customer from and against any and all losses, damages, liabilities, costs (including reasonable attorneys' fees) ("**Losses**") incurred by Customer resulting from any third-party claim, suit, action, or proceeding ("**Third-Party Claim**") that the Services, or any use of the Services in accordance with this Agreement, infringes or misappropriates such third party's US copyrights or trade secrets; provided that Customer promptly notifies Supabase in writing of the claim, cooperates with Supabase, and allows Supabase sole authority to control the defense and settlement of such claim.
2. If such a claim is made or appears possible, Customer agrees to permit Supabase, at Supabase's sole discretion: to (i) modify or replace the Services, or component or part thereof, to make it non-infringing; or (ii) obtain the right for Customer to continue use. If Supabase determines that neither alternative is reasonably commercially available, Supabase may terminate this Agreement, in its entirety or with respect to the affected component or part, effective immediately on written notice to Customer.
3. This Section 10.1 will not apply to the extent that the alleged infringement arises from: (i) use of the Services in combination with data, software, hardware, equipment, or technology not provided by Supabase or authorized by Supabase in writing; (ii) modifications to the Services not made by Supabase; (iii) Customer Data; or (iv) Third-Party Products.
### 2. Customer Indemnification.
Customer shall indemnify, hold harmless, and, at Supabase's option, defend Supabase from and against any Losses resulting from any Third-Party Claim that the Customer Data, or any use of the Customer Data in accordance with this Agreement, infringes or misappropriates such third party's US intellectual property or other rights and any Third-Party Claims based on Customer's or any Authorized User's (i) negligence or willful misconduct; (ii) use of the Services in a manner not authorized by this Agreement; or (iii) use of the Services in combination with data, software, hardware, equipment or technology not provided by Supabase or authorized by Supabase in writing; in each case provided that Customer may not settle any Third-Party Claim against Supabase unless Supabase consents to such settlement, and further provided that Supabase will have the right, at its option, to defend itself against any such Third-Party Claim or to participate in the defense thereof by counsel of its own choice.
### 3. Sole Remedy.
This section 10.3 sets forth Customer's sole remedies and Supabase's sole liability and obligation for any actual, threatened, or alleged claims that the services infringe, misappropriate, or otherwise violate any intellectual property rights of any third party.
## 11. Limitations of Liability.
Except for: (i) a party’s breach of its confidentiality obligations;
(ii) a party’s indemnity obligations; or (iii) a party’s gross negligence,
fraud, or willful misconduct ("**Excluded Liabilities**"), (a) in no
event will either party be liable under or in connection with this agreement
under any legal or equitable theory, including breach of contract, tort
(including negligence), strict liability, and otherwise, for any: (1)
consequential, incidental, indirect, exemplary, special, enhanced, or punitive
damages; (2) increased costs, diminution in value or lost business, production,
revenues, or profits; (3) loss of goodwill or reputation; (4) use, inability to
use, loss, interruption, delay or recovery of any data, or breach of data or
system security; or (5) cost of replacement goods or services, in each case
regardless of whether such party was advised of the possibility of such losses
or damages or such losses or damages were otherwise foreseeable; and (b) in no
event will either party’s aggregate liability arising out of or related to this
agreement under any legal or equitable theory, including breach of contract,
tort (including negligence), strict liability, and otherwise exceed the total
amounts paid and/or payable to Supabase under this agreement in the twelve (12)
months immediately preceding the claim; provided that, notwithstanding the
foregoing, Supabase's aggregate liability arising out of or relating to any
excluded liabilities will not exceed three times (3x) the total amounts paid
and/or payable to Supabase by Customer under this agreement in the twelve (12)
months immediately preceding the claim.
## 12. Subscription Period and Termination.
### 1. Subscription Period.
The initial term of this Agreement begins on the Effective Date and, unless terminated earlier pursuant to Section 12.2, will continue in effect for the period identified in the Order (the "**Initial Subscription Period**"). This Agreement will automatically renew for additional successive terms equal to the length of the Initial Subscription Period unless earlier terminated pursuant to this Agreement's express provisions or either Party gives the other Party written notice of non-renewal at least thirty (30) days prior to the expiration of the then-current term (each a "**Renewal Subscription Period**" and together with the Initial Subscription Period, the "**Subscription Period**").]
#### 2. Termination.
In addition to any other express termination right set forth in this Agreement:
1. Supabase may terminate this Agreement, effective on written notice to Customer, if Customer: (i) fails to pay any amount when due hereunder, and such failure continues more than ten (10) calendar days after Supabase's delivery of written notice thereof; or (ii) breaches any of its obligations under Section 2.3 or Section 6;
2. either Party may terminate this Agreement, effective on written notice to the other Party, if the other Party materially breaches this Agreement, and such breach: (i) is incapable of cure; or (ii) being capable of cure, remains uncured thirty (30) calendar days after the non-breaching Party provides the breaching Party with written notice of such breach; or
3. either Party may terminate this Agreement, effective immediately upon written notice to the other Party, if the other Party: (i) becomes insolvent or is generally unable to pay, or fails to pay, its debts as they become due; (ii) files or has filed against it, a petition for voluntary or involuntary bankruptcy or otherwise becomes subject, voluntarily or involuntarily, to any proceeding under any domestic or foreign bankruptcy or insolvency law; (iii) makes or seeks to make a general assignment for the benefit of its creditors; or (iv) applies for or has appointed a receiver, trustee, custodian, or similar agent appointed by order of any court of competent jurisdiction to take charge of or sell any material portion of its property or business.
### 3. Effect of Expiration or Termination.
Upon expiration or earlier termination of this Agreement, Customer shall immediately discontinue use of the Supabase IP and, without limiting Customer's obligations under Section 6, Customer shall delete, destroy, or return all copies of the Supabase IP and certify in writing to the Supabase that the Supabase IP has been deleted or destroyed. No expiration or termination will affect Customer's obligation to pay all Fees that may have become due before such expiration or termination or entitle Customer to any refund.
### 4. Survival.
This Section 12.4 and Sections 1, 5, 6, 8, 9, 10, 11, and 13 survive any termination or expiration of this Agreement. No other provisions of this Agreement survive the expiration or earlier termination of this Agreement.
## 13. Miscellaneous.
### 1. Entire Agreement.
This Agreement, together with any other documents incorporated herein by reference, constitutes the sole and entire agreement of the Parties with respect to the subject matter of this Agreement and supersedes all prior and contemporaneous understandings, agreements, and representations and warranties, both written and oral, with respect to such subject matter. In the event of any inconsistency between the statements made in the body of this Agreement, the related Exhibits, and any other documents incorporated herein by reference, the following order of precedence governs: (i) first, this Agreement; and (ii) second, any other documents incorporated herein by reference.
### 2. Notices.
All notices, requests, consents, claims, demands, waivers, and other communications hereunder (each, a "**Notice**") must be in writing and addressed to the Parties at the addresses set forth on the first page of this Agreement or as identified on the Order Form (or to such other address that may be designated by the Party giving Notice from time to time in accordance with this Section). All Notices must be delivered by personal delivery, nationally recognized signed for on delivery courier (with all fees pre-paid), or email (with confirmation of transmission). All email Notices to Supabase must be sent to [legal@supabase.io](mailto:legal@supabase.io). Except as otherwise provided in this Agreement, a Notice is effective only: (i) upon receipt by the receiving Party; and (ii) if the Party giving the Notice has complied with the requirements of this Section.
### 3. Force Majeure.
In no event shall either Party be liable to the other Party, or be deemed to have breached this Agreement, for any failure or delay in performing its obligations under this Agreement (except for any obligations to make payments), if and to the extent such failure or delay is caused by any circumstances beyond such Party's reasonable control, including but not limited to acts of God, flood, fire, earthquake, explosion, war, terrorism, invasion, riot or other civil unrest, strikes, labor stoppages or slowdowns or other industrial disturbances, or passage of law or any action taken by a governmental or public authority, including imposing an embargo.
### 4. Amendment and Modification.
Supabase may change this Agreement (except for any Orders) from time to time at its discretion. The date on which the Agreement was last modified will be updated at the top of this Agreement. Supabase will provide Customer with reasonable notice prior to any amendments or modifications taking effect, either by emailing the email address associated with Customer's account on the Services or by another method reasonably designed to provide notice to Customer. If Customer accesses or uses the Services after the effective date of the revised Agreement, such access and use will constitute Customer's acceptance of the revised Agreement beginning at the next Renewal Subscription Period or, if Customer enters into a new Order with Supabase, as of the date of execution of such Order.
### 5. Waiver.
No failure or delay by either Party in exercising any right or remedy available to it in connection with this Agreement will constitute a waiver of such right or remedy. No waiver under this Agreement will be effective unless made in writing and signed by an authorized representative of the Party granting the waiver.
### 6. Severability.
If any provision of this Agreement is invalid, illegal, or unenforceable in any jurisdiction, such invalidity, illegality, or unenforceability will not affect any other term or provision of this Agreement or invalidate or render unenforceable such term or provision in any other jurisdiction. Upon such determination that any term or other provision is invalid, illegal, or unenforceable, the Parties shall negotiate in good faith to modify this Agreement so as to effect their original intent as closely as possible in a mutually acceptable manner in order that the transactions contemplated hereby be consummated as originally contemplated to the greatest extent possible.
### 7. Governing Law; Submission to Jurisdiction.
This Agreement is governed by and construed in accordance with the internal laws of the State of California without giving effect to any choice or conflict of law provision or rule that would require or permit the application of the laws of any jurisdiction other than those of the State of California. Any legal suit, action, or proceeding arising out of or related to this Agreement or the licenses granted hereunder must be instituted in the federal courts of the United States or the courts of the State of California in each case located in San Francisco County, California and each Party irrevocably submits to the exclusive jurisdiction of such courts in any such suit, action, or proceeding.
### 8. Assignment.
Customer may not assign any of its rights or delegate any of its obligations hereunder, in each case whether voluntarily, involuntarily, by operation of law or otherwise, without the prior written consent of Supabase. Any purported assignment or delegation in violation of this Section will be null and void. No assignment or delegation will relieve the assigning or delegating Party of any of its obligations hereunder. This Agreement is binding upon and inures to the benefit of the Parties and their respective permitted successors and assigns.
### 9. Export Regulation.
The Services utilize software and technology that may be subject to US export control laws, including the US Export Administration Act and its associated regulations. Customer shall not, directly or indirectly, export, re-export, or release the Services or the underlying software or technology to, or make the Services or the underlying software or technology accessible from, any jurisdiction or country to which export, re-export, or release is prohibited by law, rule, or regulation. Customer shall comply with all applicable federal laws, regulations, and rules, and complete all required undertakings (including obtaining any necessary export license or other governmental approval), prior to exporting, re-exporting, releasing, or otherwise making the Services or the underlying software or technology available outside the US.
### 10. US Government Rights.
Each of the Documentation and the software components that constitute the Services is a "commercial item" as that term is defined at 48 C.F.R. § 2.101, consisting of "commercial computer software" and "commercial computer software documentation" as such terms are used in 48 C.F.R. § 12.212. Accordingly, if Customer is an agency of the US Government or any contractor therefor, Customer only receives those rights with respect to the Services and Documentation as are granted to all other end users, in accordance with (a) 48 C.F.R. § 227.7201 through 48 C.F.R. § 227.7204, with respect to the Department of Defense and their contractors, or (b) 48 C.F.R. § 12.212, with respect to all other US Government users and their contractors.
### 11. Equitable Relief.
Each Party acknowledges and agrees that a breach or threatened breach by such Party of any of its obligations under Section 6 or, in the case of Customer, Section 2.3, would cause the other Party irreparable harm for which monetary damages would not be an adequate remedy and agrees that, in the event of such breach or threatened breach, the other Party will be entitled to equitable relief, including a restraining order, an injunction, specific performance and any other relief that may be available from any court, without any requirement to post a bond or other security, or to prove actual damages or that monetary damages are not an adequate remedy. Such remedies are not exclusive and are in addition to all other remedies that may be available at law, in equity or otherwise.
### 12. Publicity.
Supabase may identify Customer as a user of the Services and may use Customer's name, logo, and other trademarks in Supabase's customer list, press releases, blog posts, advertisements, and website (and all use thereof and goodwill arising therefrom shall inure to the sole and exclusive benefit of Customer). Otherwise, neither Party may use the name, logo, or other trademarks of the other Party for any purpose without the other Party's prior written approval.
-38
View File
@@ -1,38 +0,0 @@
---
id: faq
title: FAQs
description: 'Most frequently asked questions regarding Supabase'
---
### Where do I find support?
Choose the support channel relevant for your situation here: [supabase.com/support](https://supabase.com/support)
### How much does it cost?
Self-hosting Supabase is free. If you wish to use our cloud-platform, we provide [simple, predictable pricing](https://supabase.com/pricing).
### How do I host Supabase?
You can use the docker-compose script [here](https://github.com/supabase/supabase/tree/master/docker), and find detailed instructions [here](/docs/guides/hosting/overview).
Supabase is an amalgamation of open source tools. Some of these tools are made by Supabase (like our [Realtime Server](https://github.com/supabase/realtime)), some we support directly (like [PostgREST](http://postgrest.org/en/v7.0.0/)), and some are third-party tools (like [KonSupabase is an amalgamation open sourceg](https://github.com/Kong/kong)).
All of the tools we use in Supabase are MIT, Apache 2.0, or PostgreSQL licensed. This is one of the requirements to be considered for the Supabase stack.
### How can you be a Firebase alternative if you're built with a relational database?
We started Supabase because we love the functionality of Firebase, but we personally experienced the scaling issues that many others experienced. We chose Postgres because it's well-trusted, with phenomenal scalability.
Our goal is to make Postgres as easy to use as Firebase, so that you no longer have to choose between usability and scalability.
We're sure that once you start using Postgres, you'll love it more than any other database.
### Do you support `[some other database]`?
We only support PostgreSQL. It's unlikely we'll ever move away from Postgres; however, you can [vote on a new database](https://github.com/supabase/supabase/discussions/6) if you want us to start development.
### Do you have a library for `[some other language]`?
We officially support [JavaScript](/docs/reference/javascript/installing) and [Flutter](/docs/reference/dart/installing).
You can find community-supported libraries in our [GitHub Community](https://github.com/supabase-community), and you can also help us to identify the most popular languages by [voting for a new client library](https://github.com/supabase/supabase/discussions/5).
-52
View File
@@ -1,52 +0,0 @@
---
id: going-into-prod
title: 'Production Readiness'
description: 'Things to do before making your app publicly available'
---
After developing your project and deciding it's time to Go Live With Real Users, you should run through this checklist to ensure that your project is:
- secure
- won't falter under the expected load
- remains available whilst in production
## Security
- Ensure RLS is enabled
- Tables that do not have RLS enabled with reasonable policies allow any client to access and modify their data. This is unlikely to be what you want in the majority of cases.
- [Learn more about RLS](/docs/guides/auth/row-level-security).
- Enable replication on tables containing sensitive data by enabling Row Level Security (RLS) and setting row security policies:
- Go to the Authentication > Policies page in the Supabase Dashboard to enable RLS and create security policies.
- Go to the Database > Replication page in the Supabase Dashboard to manage replication tables.
- Enable 2FA on GitHub. Since your GitHub account gives you administrative rights to your Supabase project, you should protect it with a strong password and 2FA using a U2F key or a TOTP app.
- Ensure email confirmations are enabled in the `Auth > Settings` page.
- Use a custom SMTP server for auth emails so that your users can see that the mails are coming from a trusted domain (preferably the same domain that your app is hosted on). Grab SMTP credentials from any major email provider such as SendGrid, AWS SES, etc.
- Think hard about how _you_ would abuse your service as an attacker, and mitigate.
- Review these [common cybersecurity threats](https://auth0.com/docs/security/prevent-threats).
## Performance
- Ensure that you have suitable indices to cater to your common query patterns
- [Learn more about indexes in Postgres](https://www.enterprisedb.com/postgres-tutorials/overview-postgresql-indexes).
- `pg_stat_statements` can help you [identify hot or slow queries](https://www.virtual-dba.com/blog/postgresql-performance-identifying-hot-and-slow-queries/).
- Perform load testing (preferably on a staging env)
- Tools like [k6](https://k6.io/) can simulate traffic from many different users.
- Upgrade your database if you require more resources. If you need anything beyond what is listed, contact enterprise@supabase.io.
- If you are expecting a surge in traffic (for a big launch), let the team know by sending your Project Ref to us (support@supabase.io) with more details about your launch. We'll keep an eye on your project.
## Availability
- Use your own SMTP credentials so that you have full control over the deliverability of your transactional auth emails (see Auth > Settings)
- you can grab SMTP credentials from any major email provider such as SendGrid, AWS SES, etc.
- The default rate limit for auth emails provided by Supabase is 30 new users per hour, if doing a major public announcement you will likely require more than this.
- If your application is on the free tier and is **not** expected to be queried at least once every 7 days, then it may be paused by Supabase to save on server resources.
- You can restore paused projects from the Supabase dashboard.
- Upgrade to Pro to guarantee that your project will not be paused for inactivity.
- Database backups are not available for download on the free tier.
- You can set up your own backup systems using tools like [pg_dump](https://www.postgresqltutorial.com/postgresql-backup-database/) or [wal-g](https://github.com/wal-g/wal-g).
- Nightly backups for Pro tier projects are available on the Supabase dashboard for up to 7 days.
- Upgrading to the Supabase Pro Tier will give you access to email support on support@supabase.io
## Next steps
This checklist is always growing so be sure to check back frequently, and also feel free to suggest additions and amendments by making a PR on [GitHub](https://github.com/supabase/supabase).
Whitespace-only changes.
-725
View File
@@ -1,725 +0,0 @@
---
id: about
title: GoTrue Auth Server
description: An SWT based API for managing users and issuing SWT tokens
---
GoTrue is a small open-source API written in golang, that can act as a self-standing
API service for handling user registration and authentication for JAM projects.
It's based on OAuth2 and JWT and will handle user signup, authentication and custom
user data.
## Configuration
You may configure GoTrue using either a configuration file named `.env`,
environment variables, or a combination of both. Environment variables are prefixed with `GOTRUE_`, and will always have precedence over values provided via file.
### Top-Level
```
GOTRUE_SITE_URL=https://example.netlify.com/
```
`SITE_URL` - `string` **required**
The base URL your site is located at. Currently used in combination with other settings to construct URLs used in emails.
`OPERATOR_TOKEN` - `string` _Multi-instance mode only_
The shared secret with an operator (usually Netlify) for this microservice. Used to verify requests have been proxied through the operator and
the payload values can be trusted.
`DISABLE_SIGNUP` - `bool`
When signup is disabled the only way to create new users is through invites. Defaults to `false`, all signups enabled.
`GOTRUE_RATE_LIMIT_HEADER` - `string`
Header on which to rate limit the `/token` endpoint.
### API
```
GOTRUE_API_HOST=localhost
PORT=9999
```
`API_HOST` - `string`
Hostname to listen on.
`PORT` (no prefix) / `API_PORT` - `number`
Port number to listen on. Defaults to `8081`.
`API_ENDPOINT` - `string` _Multi-instance mode only_
Controls what endpoint Netlify can access this API on.
`REQUEST_ID_HEADER` - `string`
If you wish to inherit a request ID from the incoming request, specify the name in this value.
### Database
```
GOTRUE_DB_DRIVER=mysql
DATABASE_URL=root@localhost/gotrue
```
`DB_DRIVER` - `string` **required**
Chooses what dialect of database you want. Must be `mysql`.
`DATABASE_URL` (no prefix) / `DB_DATABASE_URL` - `string` **required**
Connection string for the database.
`DB_NAMESPACE` - `string`
Adds a prefix to all table names.
**Migrations Note**
Migrations are not applied automatically, so you will need to run them after
you've built gotrue.
- If built locally: `./gotrue migrate`
- Using Docker: `docker run --rm gotrue gotrue migrate`
### Logging
```
LOG_LEVEL=debug # available without GOTRUE prefix (exception)
GOTRUE_LOG_FILE=/var/log/go/gotrue.log
```
`LOG_LEVEL` - `string`
Controls what log levels are output. Choose from `panic`, `fatal`, `error`, `warn`, `info`, or `debug`. Defaults to `info`.
`LOG_FILE` - `string`
If you wish logs to be written to a file, set `log_file` to a valid file path.
### JSON Web Tokens (JWT)
```
GOTRUE_JWT_SECRET=supersecretvalue
GOTRUE_JWT_EXP=3600
GOTRUE_JWT_AUD=netlify
```
`JWT_SECRET` - `string` **required**
The secret used to sign JWT tokens with.
`JWT_EXP` - `number`
How long tokens are valid for, in seconds. Defaults to 3600 (1 hour).
`JWT_AUD` - `string`
The default JWT audience. Use audiences to group users.
`JWT_ADMIN_GROUP_NAME` - `string`
The name of the admin group (if enabled). Defaults to `admin`.
`JWT_DEFAULT_GROUP_NAME` - `string`
The default group to assign all new users to.
### External Authentication Providers
We support `bitbucket`, `github`, `gitlab`, and `google` for external authentication.
Use the names as the keys underneath `external` to configure each separately.
```
GOTRUE_EXTERNAL_GITHUB_CLIENT_ID=myappclientid
GOTRUE_EXTERNAL_GITHUB_SECRET=clientsecretvaluessssh
```
No external providers are required, but you must provide the required values if you choose to enable any.
`EXTERNAL_X_ENABLED` - `bool`
Whether this external provider is enabled or not
`EXTERNAL_X_CLIENT_ID` - `string` **required**
The OAuth2 Client ID registered with the external provider.
`EXTERNAL_X_SECRET` - `string` **required**
The OAuth2 Client Secret provided by the external provider when you registered.
`EXTERNAL_X_REDIRECT_URI` - `string` **required for gitlab**
The URI a OAuth2 provider will redirect to with the `code` and `state` values.
`EXTERNAL_X_URL` - `string`
The base URL used for constructing the URLs to request authorization and access tokens. Used by `gitlab` only. Defaults to `https://gitlab.com`.
### E-Mail
Sending email is not required, but highly recommended for password recovery.
If enabled, you must provide the required values below.
```
GOTRUE_SMTP_HOST=smtp.mandrillapp.com
GOTRUE_SMTP_PORT=587
GOTRUE_SMTP_USER=smtp-delivery@example.com
GOTRUE_SMTP_PASS=correcthorsebatterystaple
GOTRUE_SMTP_ADMIN_EMAIL=support@example.com
GOTRUE_MAILER_SUBJECTS_CONFIRMATION="Please confirm"
```
`SMTP_ADMIN_EMAIL` - `string` **required**
The `From` email address for all emails sent.
`SMTP_HOST` - `string` **required**
The mail server hostname to send emails through.
`SMTP_PORT` - `number` **required**
The port number to connect to the mail server on.
`SMTP_USER` - `string`
If the mail server requires authentication, the username to use.
`SMTP_PASS` - `string`
If the mail server requires authentication, the password to use.
`SMTP_MAX_FREQUENCY` - `number`
Controls the minimum amount of time that must pass before sending another signup confirmation or password reset email. The value is the number of seconds. Defaults to 900 (15 minutes).
`MAILER_AUTOCONFIRM` - `bool`
If you do not require email confirmation, you may set this to `true`. Defaults to `false`.
`MAILER_SECURE_EMAIL_CHANGE_ENABLED` - `bool`
If `true`, send an email to both the user's current and new email with a confirmation link, otherwise send an email with confirmation link only to new email. Defaults to `true`.
`MAILER_URLPATHS_INVITE` - `string`
URL path to use in the user invite email. Defaults to `/`.
`MAILER_URLPATHS_CONFIRMATION` - `string`
URL path to use in the signup confirmation email. Defaults to `/`.
`MAILER_URLPATHS_RECOVERY` - `string`
URL path to use in the password reset email. Defaults to `/`.
`MAILER_URLPATHS_EMAIL_CHANGE` - `string`
URL path to use in the email change confirmation email. Defaults to `/`.
`MAILER_SUBJECTS_INVITE` - `string`
Email subject to use for user invite. Defaults to `You have been invited`.
`MAILER_SUBJECTS_CONFIRMATION` - `string`
Email subject to use for signup confirmation. Defaults to `Confirm Your Signup`.
`MAILER_SUBJECTS_RECOVERY` - `string`
Email subject to use for password reset. Defaults to `Reset Your Password`.
`MAILER_SUBJECTS_MAGIC_LINK` - `string`
Email subject to use for magic link email. Defaults to `Your Magic Link`.
`MAILER_SUBJECTS_EMAIL_CHANGE` - `string`
Email subject to use for email change confirmation. Defaults to `Confirm Email Change`.
`MAILER_TEMPLATES_INVITE` - `string`
URL path to an email template to use when inviting a user.
`SiteURL`, `Email`, and `ConfirmationURL` variables are available.
Default Content (if template is unavailable):
```html
<h2>You have been invited</h2>
<p>
You have been invited to create a user on {{ .SiteURL }}. Follow this link to
accept the invite:
</p>
<p><a href="{{ .ConfirmationURL }}">Accept the invite</a></p>
```
`MAILER_TEMPLATES_CONFIRMATION` - `string`
URL path to an email template to use when confirming a signup.
`SiteURL`, `Email`, and `ConfirmationURL` variables are available.
Default Content (if template is unavailable):
```html
<h2>Confirm your signup</h2>
<p>Follow this link to confirm your user:</p>
<p><a href="{{ .ConfirmationURL }}">Confirm your mail</a></p>
```
`MAILER_TEMPLATES_RECOVERY` - `string`
URL path to an email template to use when resetting a password.
`SiteURL`, `Email`, and `ConfirmationURL` variables are available.
Default Content (if template is unavailable):
```html
<h2>Reset Password</h2>
<p>Follow this link to reset the password for your user:</p>
<p><a href="{{ .ConfirmationURL }}">Reset Password</a></p>
```
`MAILER_TEMPLATES_MAGIC_LINK` - `string`
URL path to an email template to use when sending magic link.
`SiteURL`, `Email`, and `ConfirmationURL` variables are available.
Default Content (if template is unavailable):
```html
<h2>Magic Link</h2>
<p>Follow this link to login:</p>
<p><a href="{{ .ConfirmationURL }}">Log In</a></p>
```
`MAILER_TEMPLATES_EMAIL_CHANGE` - `string`
URL path to an email template to use when confirming the change of an email address.
`SiteURL`, `Email`, `NewEmail`, and `ConfirmationURL` variables are available.
Default Content (if template is unavailable):
```html
<h2>Confirm Change of Email</h2>
<p>
Follow this link to confirm the update of your email from {{ .Email }} to {{
.NewEmail }}:
</p>
<p><a href="{{ .ConfirmationURL }}">Change Email</a></p>
```
## Endpoints
GoTrue exposes the following endpoints:
### **GET /settings**
Returns the publicly available settings for this gotrue instance.
```json
{
"external": {
"bitbucket": true,
"github": true,
"gitlab": true,
"google": true
},
"disable_signup": false,
"autoconfirm": false
}
```
### **POST /signup**
Register a new user with an email and password.
```json
{
"email": "email@example.com",
"password": "secret"
}
```
Returns:
```json
{
"id": "11111111-2222-3333-4444-5555555555555",
"email": "email@example.com",
"confirmation_sent_at": "2016-05-15T20:49:40.882805774-07:00",
"created_at": "2016-05-15T19:53:12.368652374-07:00",
"updated_at": "2016-05-15T19:53:12.368652374-07:00"
}
```
### **POST /invite**
Invites a new user with an email.
This endpoint requires the `service_role` or `supabase_admin` JWT set as an Auth Bearer header:
e.g.
```json
headers: {
"Authorization" : "Bearer eyJhbGciOiJI...M3A90LCkxxtX9oNP9KZO"
}
```
```json
{
"email": "email@example.com"
}
```
Returns:
```json
{
"id": "11111111-2222-3333-4444-5555555555555",
"email": "email@example.com",
"confirmation_sent_at": "2016-05-15T20:49:40.882805774-07:00",
"created_at": "2016-05-15T19:53:12.368652374-07:00",
"updated_at": "2016-05-15T19:53:12.368652374-07:00",
"invited_at": "2016-05-15T19:53:12.368652374-07:00"
}
```
### **POST /verify**
Verify a registration or a password recovery. Type can be `signup` or `recovery` or `invite`
and the `token` is a token returned from either `/signup` or `/recover`.
```json
{
"type": "signup",
"token": "confirmation-code-delivered-in-email"
}
```
`password` is required for signup verification if no existing password exists.
Returns:
```json
{
"access_token": "jwt-token-representing-the-user",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "a-refresh-token",
"type": "signup | recovery | invite"
}
```
### **GET /verify**
Verify a registration or a password recovery. Type can be `signup` or `recovery` or `magiclink` or `invite`
and the `token` is a token returned from either `/signup` or `/recover` or `/magiclink`.
query params:
```json
{
"type": "signup",
"token": "confirmation-code-delivered-in-email"
}
```
User will be logged in and redirected to:
```json
SITE_URL/#access_token=jwt-token-representing-the-user&token_type=bearer&expires_in=3600&refresh_token=a-refresh-token&type=invite
```
Your app should detect the query params in the fragment and use them to set the session (supabase-js does this automatically)
You can use the `type` param to redirect the user to a password set form in the case of `invite` or `recovery`,
or show an account confirmed/welcome message in the case of `signup`, or direct them to some additional onboarding flow
### **POST /magiclink**
Magic Link. Will deliver a link (e.g. `/verify?type=magiclink&token=fgtyuf68ddqdaDd`) to the user based on
email address which they can use to redeem an access_token.
By default Magic Links can only be sent once every 60 seconds
```json
{
"email": "email@example.com"
}
```
Returns:
```json
{}
```
when clicked the magic link will redirect the user to `<SITE_URL>#access_token=x&refresh_token=y&expires_in=z&token_type=bearer&type=magiclink` (see `/verify` above)
### **POST /recover**
Password recovery. Will deliver a password recovery mail to the user based on
email address.
By default recovery links can only be sent once every 60 seconds
```json
{
"email": "email@example.com"
}
```
Returns:
```json
{}
```
### **POST /token**
This is an OAuth2 endpoint that currently implements
the password and refresh_token grant types
query params:
```
?grant_type=password
```
body:
```json
{
"email": "name@domain.com",
"password": "somepassword"
}
```
or
query params:
```
grant_type=refresh_token
```
body:
```json
{
"refresh_token": "a-refresh-token"
}
```
Once you have an access token, you can access the methods requiring authentication
by settings the `Authorization: Bearer YOUR_ACCESS_TOKEN_HERE` header.
Returns:
```json
{
"access_token": "jwt-token-representing-the-user",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "a-refresh-token"
}
```
### **GET /user**
Get the JSON object for the logged in user (requires authentication)
Returns:
```json
{
"id": "11111111-2222-3333-4444-5555555555555",
"email": "email@example.com",
"confirmation_sent_at": "2016-05-15T20:49:40.882805774-07:00",
"created_at": "2016-05-15T19:53:12.368652374-07:00",
"updated_at": "2016-05-15T19:53:12.368652374-07:00"
}
```
### **PUT /user**
Update a user (Requires authentication). Apart from changing email/password, this
method can be used to set custom user data.
```json
{
"email": "new-email@example.com",
"password": "new-password",
"data": {
"key": "value",
"number": 10,
"admin": false
}
}
```
Returns:
```json
{
"id": "11111111-2222-3333-4444-5555555555555",
"email": "email@example.com",
"confirmation_sent_at": "2016-05-15T20:49:40.882805774-07:00",
"created_at": "2016-05-15T19:53:12.368652374-07:00",
"updated_at": "2016-05-15T19:53:12.368652374-07:00"
}
```
### **POST /admin/users**
Creates a new user. Requires your `service_role` API key and thus should only be
used in secure server-side environments.
```json
{
"email": "new-email@example.com",
"password": "new-password",
"data": {
"key": "value",
"number": 10,
"admin": false
}
}
```
Returns:
```json
{
"id": "11111111-2222-3333-4444-5555555555555",
"aud": "authenticated",
"role": "authenticated",
"email": "email@example.com",
"app_metadata": {
"provider": "email"
},
"user_metadata": null,
"created_at": "2016-05-15T19:53:12.368652374-07:00",
"updated_at": "2016-05-15T19:53:12.368652374-07:00"
}
```
### **GET /admin/users/{user_id}**
Gets a user. Requires your `service_role` API key and thus should only be used
in secure server-side environments.
Returns:
```json
{
"id": "11111111-2222-3333-4444-5555555555555",
"aud": "authenticated",
"role": "authenticated",
"email": "email@example.com",
"app_metadata": {
"provider": "email"
},
"user_metadata": {},
"created_at": "2016-05-15T19:53:12.368652374-07:00",
"updated_at": "2016-05-15T19:53:12.368652374-07:00"
}
```
### **PUT /admin/users/{user_id}**
Updates a user. Requires your `service_role` API key and thus should only be
used in secure server-side environments.
```json
{
"email": "email@example.com",
"password": "updated-password",
"data": {
"key": "updated-value",
"number": 10,
"admin": false
}
}
```
Returns:
```json
{
"id": "11111111-2222-3333-4444-5555555555555",
"aud": "authenticated",
"role": "authenticated",
"email": "email@example.com",
"app_metadata": {
"provider": "email"
},
"user_metadata": {},
"created_at": "2016-05-15T19:53:12.368652374-07:00",
"updated_at": "2016-05-15T19:53:12.368652374-07:00"
}
```
### **POST /admin/generate_link**
Returns the corresponding email action link based on the type specified. The response also contains the query params of the action link as separate JSON fields for convenience (along with the email OTP from which the corresponding token is generated).
Returns:
```js
{
"action_link": "http://localhost:9999/verify?token=TOKEN&type=TYPE&redirect_to=REDIRECT_URL",
"email_otp": "EMAIL_OTP",
"hashed_token": "TOKEN",
"verification_type": "TYPE",
"redirect_to": "REDIRECT_URL",
...
}
```
### **DELETE /admin/users/{user_id}**
Deletes a user. Requires your `service_role` API key and thus should only be
used in secure server-side environments.
### **POST /logout**
Logout a user (Requires authentication).
This will revoke all refresh tokens for the user. Remember that the JWT tokens
will still be valid for stateless auth until they expires.
### **GET /authorize**
Get access_token from external oauth provider
query params:
```
provider=google | bitbucket | github | gitlab
```
Redirects to provider and then to `/callback`
### **GET /callback**
External provider should redirect to here
Redirects to `<GOTRUE_SITE_URL>#access_token=<access_token>&refresh_token=<refresh_token>&expires_in=3600&provider=<provider_name>`
## Pre-built
- [Docker](https://hub.docker.com/repository/docker/supabase/gotrue)
@@ -1,66 +0,0 @@
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
import UserManagementSQLTemplate from './user_management_quickstart_sql_template.md'
## Project set up
Before we start building we're going to set up our Database and API. This is as simple as starting a new Project in Supabase
and then creating a "schema" inside the database.
### Create a project
1. Go to [app.supabase.com](https://app.supabase.com).
1. Click on "New Project".
1. Enter your project details.
1. Wait for the new database to launch.
### Set up the database schema
Now we are going to set up the database schema. We can use the "User Management Starter" quickstart in the SQL Editor,
or you can just copy/paste the SQL from below and run it yourself.
<Tabs
groupId="language"
defaultValue="dashboard"
values={[
{label: 'Dashboard', value: 'dashboard'},
{label: 'SQL', value: 'sql'},
]}>
<TabItem value="dashboard">
1. Go to the [SQL Editor](https://app.supabase.com/project/_/sql) page in the Dashboard.
2. Click **User Management Starter**.
3. Click **Run**.
<video width="99%" muted playsInline controls="true">
<source
src="/docs/videos/sql-user-management-starter.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
</TabItem>
<TabItem value="sql">
<UserManagementSQLTemplate />
</TabItem>
</Tabs>
### Get the API Keys
Now that you've created some database tables, you are ready to insert data using the auto-generated API.
We just need to get the URL and `anon` key from the API settings.
1. Go to the [Settings](https://app.supabase.com/project/_/settings) page in the Dashboard.
2. Click **API** in the sidebar.
3. Find your API `URL`, `anon`, and `service_role` keys on this page.
<video width="99%" muted playsInline controls="true">
<source
src="/docs/videos/api/api-url-and-key.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
@@ -1,11 +0,0 @@
## Intro
This example provides the steps to build a basic user management app. It includes:
- Supabase [Database](/docs/guides/database): a Postgres database for storing your user data.
- Supabase [Auth](/docs/guides/auth): users can sign in with magic links (no passwords, only email).
- Supabase [Storage](/docs/guides/storage): users can upload a photo.
- [Row Level Security](/docs/guides/auth#row-level-security): data is protected so that individuals can only access their own data.
- Instant [APIs](/docs/guides/api): APIs will be automatically generated when you create your database tables.
By the end of this guide you'll have an app which allows users to login and update some basic profile details:
@@ -1,55 +0,0 @@
```sql
-- Create a table for public profiles
create table profiles (
id uuid references auth.users not null primary key,
updated_at timestamp with time zone,
username text unique,
full_name text,
avatar_url text,
website text,
constraint username_length check (char_length(username) >= 3)
);
-- Set up Row Level Security (RLS)
-- See https://supabase.com/docs/guides/auth/row-level-security for more details.
alter table profiles
enable row level security;
create policy "Public profiles are viewable by everyone." on profiles
for select using (true);
create policy "Users can insert their own profile." on profiles
for insert with check (auth.uid() = id);
create policy "Users can update own profile." on profiles
for update using (auth.uid() = id);
-- This trigger automatically creates a profile entry when a new user signs up via Supabase Auth.
-- See https://supabase.com/docs/guides/auth/managing-user-data#using-triggers for more details.
create function public.handle_new_user()
returns trigger as $$
begin
insert into public.profiles (id, full_name, avatar_url)
values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url');
return new;
end;
$$ language plpgsql security definer;
create trigger on_auth_user_created
after insert on auth.users
for each row execute procedure public.handle_new_user();
-- Set up Storage!
insert into storage.buckets (id, name)
values ('avatars', 'avatars');
-- Set up access controls for storage.
-- See https://supabase.com/docs/guides/storage#policy-examples for more details.
create policy "Avatar images are publicly accessible." on storage.objects
for select using (bucket_id = 'avatars');
create policy "Anyone can upload an avatar." on storage.objects
for insert with check (bucket_id = 'avatars');
create policy "Anyone can update their own avatar." on storage.objects
for update using (auth.uid() = owner) with check (bucket_id = 'avatars');
```
-411
View File
@@ -1,411 +0,0 @@
---
id: api
title: Serverless APIs
description: Auto-generating and Realtime APIs.
sidebar_label: Overview
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
import useBaseUrl from '@docusaurus/useBaseUrl'
Supabase auto-generates three types of API directly from your database schema.
- REST - interact with your database through a restful interface.
- Realtime - listen to database changes.
- GraphQL - [in beta](https://supabase.com/blog/pg-graphql).
The APIs are:
- **Instant and auto-generated.** <br />As you update your database the changes are immediately accessible through your API.
- **Self documenting.** <br />Supabase generates documentation in the Dashboard which updates as you make database changes.
- **Secure.** <br />The API is configured to work with PostgreSQL's Row Level Security, provisioned behind an API gateway with key-auth enabled.
- **Fast.** <br />Our benchmarks for basic reads are more than 300% faster than Firebase. The API is a very thin layer on top of Postgres, which does most of the heavy lifting.
- **Scalable.** <br />The API can serve thousands of simultaneous requests, and works well for Serverless workloads.
## REST API {#rest-api-overview}
Supabase provides a RESTful API using [PostgREST](https://postgrest.org/). This is a very thin API layer on top of Postgres.
It provides everything you need from a CRUD API:
- Basic CRUD operations
- Deeply nested joins, allowing you to fetch data from multiple tables in a single fetch
- Works with Postgres Views
- Works with Postgres Functions
- Works with the Postgres security model - including Row Level Security, Roles, and Grants.
<div class="video-container">
<iframe
src="https://www.youtube-nocookie.com/embed/rPAJJFdtPw0"
frameBorder="1"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
></iframe>
</div>
## GraphQL API {#graphql-api-overview}
:::note
GraphQL is in Beta, and may have breaking changes. It is only available on self-hosted setups and Supabase projects created after 28th March 2022.
:::
GraphQL in Supabase works through [pg_graphql](https://supabase.com/blog/pg-graphql), an open source PostgreSQL extension for GraphQL.
## Realtime API {#realtime-api-overview}
Supabase provides a Realtime API using [Realtime](https://github.com/supabase/realtime). You can use this to listen to database changes over websockets.
Realtime leverages PostgreSQL's built-in logical replication. You can manage your Realtime API simply by managing Postgres publications.
## Getting started
All APIs are auto-created from Database tables. After you have added tables or functions to your database, you can use the APIs provided.
### Creating API Routes
API routes are automatically created when you create Postgres Tables, Views, or Functions.
Let's create our first
API route by creating a table called `todos` to store tasks.
This creates a corresponding route `todos` which can accept `GET`, `POST`, `PATCH`, & `DELETE` requests.
<Tabs
groupId="dashboard-or-sql"
defaultValue="dashboard"
values={[
{label: 'Dashboard', value: 'dashboard'},
{label: 'SQL', value: 'sql'},
]}>
<TabItem value="dashboard">
1. Go to the [Table editor](https://app.supabase.com/project/_/editor) page in the Dashboard.
1. Click **New Table** and create a table with the name `todos`.
1. Click **Save**.
1. Click **New Column** and create a column with the name `task` and type `text`.
1. Click **Save**.
<video width="99%" muted playsInline controls="true">
<source
src={useBaseUrl('/videos/api/api-create-table-sm.mp4')}
type="video/mp4"
muted
playsInline
/>
</video>
</TabItem>
<TabItem value="sql">
```sql
-- Create a table called "todos" with a column to store tasks.
create table todos (
id bigint generated by default as identity primary key,
task text check (char_length(task) > 3)
);
```
</TabItem>
</Tabs>
### API URL and Keys
Every Supabase project has a unique API URL. Your API is secured behind an API gateway which requires an API Key for every request.
1. Go to the [Settings](https://app.supabase.com/project/_/settings/general) page in the Dashboard.
2. Click **API** in the sidebar.
3. Find your API `URL`, `anon`, and `service_role` keys on this page.
<video width="99%" muted playsInline controls="true">
<source
src={useBaseUrl('/videos/api/api-url-and-key.mp4')}
type="video/mp4"
muted
playsInline
/>
</video>
The REST API and the GraphQL API are both accessible through this URL:
- REST: `https://<project_ref>.supabase.co/rest/v1`
- GraphQL: `https://<project_ref>.supabase.co/graphql/v1`
Both of these routes require the `anon` key to be passed through an `apikey` header.
#### API Keys
You are provided with two keys:
- an `anon` key, which is safe to be used in a browser context.
- a `service_role` key, which should only be used on a server. This key can bypass Row Level Security. NEVER use this key in a browser.
### Accessing the docs in the Dashboard
#### REST API {#rest-api-dashboard-docs}
Supabase generates documentation in the [Dashboard](https://app.supabase.com) which updates as you make database changes.
Let's view the documentation for a `countries` table which we created in our database.
1. Go to the [API](https://app.supabase.com/project/_/api) page in the Dashboard.
2. Find the `countries` table under **Tables and Views** in the sidebar.
3. Switch between the JavaScript and the cURL docs using the tabs.
<video width="99%" muted playsInline controls="true">
<source
src={useBaseUrl('/videos/api/api-docs.mp4')}
type="video/mp4"
muted
playsInline
/>
</video>
#### GraphQL
The GraphQL Endpoint that we provide (`https://<project_ref>.supabase.co/graphql/v1`) is compatible with any GraphiQL implementation that can pass an `apikey` header.
Some suggested applications:
- [paw.cloud](https://paw.cloud)
- [insomnia.rest](https://insomnia.rest)
- [postman.com/graphql](https://www.postman.com/graphql/)
- Self-hosted GraphiQL: GraphiQL can be served through a simple HTML file. See [this discussion](https://github.com/supabase/supabase/discussions/6144) for more details.
## Using the API
### REST API
You can interact with your API directly via HTTP requests, or you can use the client libraries which we provide.
Let's see how to make a request to the `todos` table which we created in the first step,
using the API URL (`SUPABASE_URL`) and Key (`SUPABASE_ANON_KEY`) we provided:
<Tabs
groupId="language"
defaultValue="javascript"
values={[
{label: 'JavaScript', value: 'javascript'},
{label: 'cURL', value: 'curl'},
]}>
<TabItem value="javascript">
```javascript
// Initialize the JS client
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY)
// Make a request
const { data: todos, error } = await supabase.from('todos').select('*')
```
</TabItem>
<TabItem value="curl">
```bash
# Append /rest/v1/ to your URL, and then use the table name as the route
curl '<SUPABASE_URL>/rest/v1/todos' \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>"
```
</TabItem>
</Tabs>
JS Reference: [select()](../reference/javascript/select),
[insert()](../reference/javascript/insert),
[update()](../reference/javascript/update),
[upsert()](../reference/javascript/upsert),
[delete()](../reference/javascript/delete),
[rpc()](../reference/javascript/rpc) (call Postgres functions).
### GraphQL API
You can use any GraphQL client with the Supabase GraphQL API. For our GraphQL example we will use [urql](https://formidable.com/open-source/urql/docs/).
<Tabs
groupId="language"
defaultValue="javascript"
values={[
{label: 'JavaScript', value: 'javascript'},
{label: 'cURL', value: 'curl'},
]}>
<TabItem value="javascript">
```javascript
import { createClient, useQuery } from 'urql'
// Prepare API key and Authorization header
const headers = {
apikey: <SUPABASE_ANON_KEY>,
authorization: `Bearer ${<SUPABASE_ANON_KEY}`>
}
// Create GraphQL client
// See: https://formidable.com/open-source/urql/docs/basics/react-preact/#setting-up-the-client
const client = createClient({
url: '<SUPABASE_URL>/graphql/v1',
fetchOptions: function createFetchOptions() {
return { headers }
},
})
// Prepare our GraphQL query
const TodosQuery = `
query {
todosCollection {
edges {
node {
id
title
}
}
}
}
`
// Query for the data (React)
const [result, reexecuteQuery] = useQuery({
query: TodosQuery,
})
// Read the result
const { data, fetching, error } = result
```
</TabItem>
<TabItem value="curl">
```bash
# Append /graphql/v1/ to your URL, and then use the table name as the route
curl --request POST '<SUPABASE_URL>/graphql/v1' \
-H 'apikey: <SUPABASE_ANON_KEY>' \
-H 'Authorization: Bearer <SUPABASE_ANON_KEY>' \
-d '{ "query":"{ todos(first: 3) { edges { node { id } } } }" }'
```
</TabItem>
</Tabs>
### Realtime API
By default Realtime is disabled on your database. Let's turn on Realtime for the `todos` table.
<Tabs
groupId="dashboard-or-sql"
defaultValue="dashboard"
values={[
{label: 'Dashboard', value: 'dashboard'},
{label: 'SQL', value: 'sql'},
]}>
<TabItem value="dashboard">
1. Go to the [Database](https://app.supabase.com/project/_/database/tables) page in the Dashboard.
2. Click on **Replication** in the sidebar.
3. Control which database events are sent by toggling **Insert**, **Update**, and **Delete**.
4. Control which tables broadcast changes by selecting **Source** and toggling each table.
<video width="99%" muted playsInline controls="true">
<source
src={useBaseUrl('/videos/api/api-realtime.mp4')}
type="video/mp4"
muted
playsInline
/>
</video>
</TabItem>
<TabItem value="sql">
```sql
alter publication supabase_realtime add table todos;
```
</TabItem>
</Tabs>
From the client, we can listen to any new data that is inserted into the `todos` table:
```javascript
// Initialize the JS client
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY)
// Create a function to handle inserts
const handleInserts = (payload) => {
console.log('Change received!', payload)
}
// Listen to inserts
const { data: todos, error } = await supabase
.from('todos')
.on('INSERT', handleInserts)
.subscribe()
```
Use [subscribe()](/docs/reference/javascript/subscribe) to listen to database changes.
The Realtime API works through PostgreSQL's replication functionality. Postgres sends database changes to a [publication](/docs/guides/database/replication#publications)
called `supabase_realtime`, and by managing this publication you can control which data is broadcast.
## API Security
### Securing your Routes
Your API is designed to work with Postgres Row Level Security (RLS). If you use Supabase [Auth](/guides/auth), you can restrict data based on the logged-in user.
To control access to your data, you can use [Policies](/guides/auth#policies).
When you create a table in Postgres, Row Level Security is disabled by default. To enable RLS:
<Tabs
groupId="dashboard-or-sql"
defaultValue="dashboard"
values={[
{label: 'Dashboard', value: 'dashboard'},
{label: 'SQL', value: 'sql'},
]}>
<TabItem value="dashboard">
1. Go to the [Authentication](https://app.supabase.com/project/_/auth/users) page in the Dashboard.
2. Click on **Policies** in the sidebar.
3. Select **Enable RLS** to enable Row Level Security.
</TabItem>
<TabItem value="sql">
```sql
alter table todos enable row level security;
```
</TabItem>
</Tabs>
### The `service_role` key
Never expose the `service_role` key in a browser or anywhere where a user can see it. This Key is designed to bypass Row Level Security - so it should only be used on a private server.
A common use case for the `service_role` key is to run data analytics jobs on the backend. To support joins on user id, it is often useful to grant the service role read access to `auth.users` table.
```sql
grant select on table auth.users to service_role;
```
We have [partnered with GitHub](https://github.blog/changelog/2022-03-28-supabase-is-now-a-github-secret-scanning-partner/) to scan for Supabase `service_role` keys pushed to public repositories.
If they detect any keys with service_role privileges being pushed to GitHub, they will forward the API key to us, so that we can automatically revoke the detected secrets and notify you, protecting your data against malicious actors.
### Safeguards towards accidental deletes and updates
For all projects, by default, the Postgres extension [safeupdate](https://github.com/eradman/pg-safeupdate) is enabled for all queries coming from the API.
This ensures that any `delete()` or `update()` would fail if there are no accompanying filters provided.
To confirm that safeupdate is enabled for queries going through the API of your project, the following query could be run:
```sql
select usename,useconfig from pg_shadow where usename = 'authenticator' ;
```
The expected value for `useconfig` should be:
```
["session_preload_libraries=supautils, safeupdate"]
```
@@ -1,110 +0,0 @@
---
id: generating-types
title: 'Generating Types'
description: How to generate types for your API and Supabase libraries.
---
Supabase APIs are generated from your database, which means that we can use database introspection to generate type-safe API definitions.
### Generating types using Supabase CLI
The Supabase CLI is a single binary Go application that provides everything you need to setup a local development environment.
You can [install the CLI](https://www.npmjs.com/package/supabase) via npm or other supported package managers. The minimum required version of the CLI is [v1.8.1](https://github.com/supabase/cli/releases).
```bash
npm i supabase@">=1.8.1" --save-dev
```
Login with your Personal Access Token
```bash
npx supabase login
```
Generate types for your project to produce the file `types/supabase.ts`
```bash
npx supabase gen types typescript --project-id "$PROJECT_ID" --schema public > types/supabase.ts
```
After you have generated your types, you can use them in `src/index.ts`
```tsx
import { NextApiRequest, NextApiResponse } from 'next'
import { createClient } from '@supabase/supabase-js'
import { Database } from '../types/supabase'
const supabase = createClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.SUPABASE_SECRET_KEY
)
export default async (req: NextApiRequest, res: NextApiResponse) => {
const allOnlineUsers = await supabase
.from('users')
.select('*')
.eq('status', 'ONLINE')
res.status(200).json(allOnlineUsers)
}
```
## Update types automatically with GitHub Actions
One way to keep your type definitions in sync with your database is to set up a GitHub action that runs on a schedule.
Add the script above to your `package.json` to run it using `npm run update-types`
```json
"update-types": "npx supabase gen types typescript --project-id \"$PROJECT_ID\" > types/supabase.ts"
```
Create a file `.github/workflows/update-types.yml` with the following snippet to define the action along with the environment variables. This script will commit new type changes to your repo every night.
```yaml
name: Update database types
on:
schedule:
# sets the action to run daily. You can modify this to run the action more or less frequently
- cron: '0 0 * * *'
jobs:
update:
runs-on: ubuntu-latest
env:
SUPABASE_ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
PROJECT_ID: <your-project-id>
steps:
- uses: actions/checkout@v2
with:
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-node@v2.1.5
with:
node-version: 16
- run: npm run update-types
- name: check for file changes
id: git_status
run: |
echo "::set-output name=status::$(git status -s)"
- name: Commit files
if: ${{contains(steps.git_status.outputs.status, ' ')}}
run: |
git add types/database/index.ts
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git commit -m "Update database types" -a
- name: Push changes
if: ${{contains(steps.git_status.outputs.status, ' ')}}
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.ref }}
```
Alternatively, you can use a community-supported GitHub action: [generate-supabase-db-types-github-action](https://github.com/lyqht/generate-supabase-db-types-github-action).
## Resources
- [Generating Supabase types with GitHub Actions](https://blog.esteetey.dev/how-to-create-and-test-a-github-action-that-generates-types-from-supabase-database)
-196
View File
@@ -1,196 +0,0 @@
---
id: auth
title: Auth
description: Use Supabase to Authenticate and Authorize your users.
sidebar_label: Overview
---
import Link from '@docusaurus/Link'
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
import providers from '@site/src/data/authProviders'
import ButtonCard from '@site/src/components/ButtonCard'
import useBaseUrl from '@docusaurus/useBaseUrl'
## Overview
There are two parts to every Auth system:
- **Authentication:** should this person be allowed in? If yes, who are they?
- **Authorization:** once they are in, what are they allowed to do?
Supabase Auth is designed to work either as a standalone product, or deeply integrated with the other Supabase products.
Postgres is at the heart of everything we do, and the Auth system follows this principle. We leverage Postgres' built-in Auth functionality wherever possible.
Here's a quick, 2 minute tour of the Auth features built-in to Supabase:
<div class="video-container">
<iframe
src="https://www.youtube-nocookie.com/embed/6ow_jW4epf8"
frameBorder="1"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
></iframe>
</div>
## Authentication
You can authenticate your users in several ways:
- Email & password.
- Magic links (one-click logins).
- Social providers.
- Phone logins.
### Providers
We provide a suite of Providers and login methods, as well as [Auth helpers](/docs/guides/auth/auth-helpers/).
<div class="container" style={{ padding: 0 }}>
<div class="row is-multiline">
{providers.map((x) => (
<div key={x.name} class="col col--6">
<ButtonCard
class="card"
to={useBaseUrl(x.href)}
title={x.name}
style={{ height: '100%' }}
>
<div class="button-card__inner">
<div
class=""
style={{
display: 'flex',
justifyContent: 'space-between',
gap: 10,
}}
>
{x.logo && <img src={x.logo} alt={x.name} width="20" />}
<p>{x.name}</p>
<p>
{x.official ? (
<span class={`badge badge--official`}>Official</span>
) : (
<span class={`badge badge--unofficial`}>Unofficial</span>
)}
</p>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 5 }}>
<div
class="code-block"
style={{
width: '100%',
display: 'flex',
justifyContent: 'space-between',
fontSize: '0.7rem',
}}
>
<span>Platform:</span>
<span>{x.platform.toString()}</span>
</div>
<div
class="code-block"
style={{
width: '100%',
display: 'flex',
justifyContent: 'space-between',
fontSize: '0.7rem',
}}
>
<span>Self-Hosted:</span>
<span>{x.selfHosted.toString()}</span>
</div>
</div>
</div>
</ButtonCard>
</div>
))}
</div>
</div>
### Configure third-party providers
You can enable third-party providers with the click of a button by navigating to Authentication > Settings > Auth Providers and inputting your `Client ID` and `Secret` for each.
![OAuth Logins.](/img/supabase-oauth-logins.png)
## Authorization
When you need granular authorization rules, nothing beats PostgreSQL's Row Level Security (RLS).
Policies are PostgreSQL's rule engine. They are incredibly powerful and flexible, allowing you to write complex SQL rules which fit your unique business needs.
Get started with our [Row Level Security Guides](/docs/guides/auth/row-level-security).
### Row Level Security
Authentication only gets you so far. When you need granular authorization rules, nothing beats PostgreSQL's [Row Level Security (RLS)](https://www.postgresql.org/docs/current/ddl-rowsecurity.html). Supabase makes it simple to turn RLS on and off.
<video width="99%" muted playsInline controls="true">
<source src="/docs/videos/rls-zoom2.mp4" type="video/mp4" muted playsInline />
</video>
### Policies
[Policies](https://www.postgresql.org/docs/current/sql-createpolicy.html) are PostgreSQL's rule engine. They are incredibly powerful and flexible, allowing you to write complex SQL rules which fit your unique business needs.
<video width="99%" muted playsInline controls="true">
<source
src="/docs/videos/policies-zoom2.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
With policies, your database becomes the rules engine. Instead of repetitively filtering your queries, like this ...
```js
const loggedInUserId = 'd0714948'
let { data, error } = await supabase
.from('users')
.select('user_id, name')
.eq('user_id', loggedInUserId)
// console.log(data)
// => { id: 'd0714948', name: 'Jane' }
```
... you can simply define a rule on your database table, `auth.uid() = user_id`, and your request will return the rows which pass the rule, even when you remove the filter from your middleware:
```js
let { data, error } = await supabase.from('users').select('user_id, name')
// console.log(data)
// Still => { id: 'd0714948', name: 'Jane' }
```
### How It Works
1. A user signs up. Supabase creates a new user in the `auth.users` table.
2. Supabase returns a new JWT, which contains the user's `UUID`.
3. Every request to your database also sends the JWT.
4. Postgres inspects the JWT to determine the user making the request.
5. The user's UID can be used in policies to restrict access to rows.
Supabase provides a special function in Postgres, `auth.uid()`, which extracts the user's UID from the JWT. This is especially useful when creating policies.
## User Management
Supabase provides multiple endpoints to authenticate and manage your users:
- [Sign up](/docs/reference/javascript/auth-signup)
- [Sign in with password](/docs/reference/javascript/auth-signinwithpassword)
- [Sign in with passwordless / one-time password (OTP)](/docs/reference/javascript/auth-signinwithotp)
- [Sign in with OAuth](/docs/reference/javascript/auth-signinwithoauth)
- [Sign out](/docs/reference/javascript/auth-signout)
When users sign up, Supabase assigns them a unique ID. You can reference this ID anywhere in your database. For example, you might create a `profiles` table referencing `id` in the `auth.users` table using a `user_id` field.
<video width="99%" muted playsInline controls="true">
<source
src="/docs/videos/auth-zoom2.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
@@ -1,209 +0,0 @@
---
id: auth-apple
title: 'Login with Apple'
description: Add Apple OAuth to your Supabase project
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
To enable Apple Auth for your project, you need to set up an Apple OAuth application and add the application credentials to your Supabase Dashboard.
## Overview
Apple OAuth consists of six broad steps:
- Obtaining an `App Id` with “Sign In with Apple” capabilities.
- Obtaining a `Services Id` - this will serve as the `client_id`.
- Obtaining a `secret key` that will be used to get our `client_secret`.
- Generating the `client_secret` using the `secret key`.
- Add your `client id` and `client secret` keys to your [Supabase Project](https://app.supabase.com).
- Add the login code to your [Supabase JS Client App](https://github.com/supabase/supabase-js).
## Access your Apple Developer account
- Go to [developer.apple.com](https://developer.apple.com).
- Click on `Account` at the top right to log in.
![Apple Developer Portal.](/img/guides/auth-apple/apple-developer-portal.png)
## Obtain an App ID
- Go to `Certificates, Identifiers & Profiles`.
- Click on `Identifiers` at the left.
- Click on the `+` sign in the upper left next to `Identifiers`.
- Select `App IDs` and click `Continue`.
- Select type `App` and click `Continue`.
- Fill out your app information:
- App description.
- Bundle ID (Apple recommends reverse-domain name style, so if your domain is acme.com and your app is called roadrunner, use: "com.acme.roadrunner").
- Scroll down and check `Sign In With Apple`.
- Click `Continue` at the top right.
- Click `Register` at the top right.
## Obtain a Services ID
This will serve as the `client_id` when you make API calls to authenticate the user.
- Go to `Certificates, Identifiers & Profiles`.
- Click on `Identifiers` at the left.
- Click on the `+` sign in the upper left next to `Identifiers`.
- Select `Services IDs` and click `Continue`.
- Fill out your information:
- App description.
- Bundle ID (you can't use the same Bundle ID from the previous step, but you can just add something to the beginning, such as "app." to make it app.com.acme.roadrunner").
- SAVE THIS ID -- this ID will become your `client_id` later.
- Click `Continue` at the top right.
- Click `Register` at the top right.
## Find your callback URL
The next step requires a callback URL, which looks like this:
`https://<project-ref>.supabase.co/auth/v1/callback`
- Go to your [Supabase Project Dashboard](https://app.supabase.com).
- Click on the `Settings` icon at the bottom of the left sidebar.
- Click on `API` in the list.
- Under Config / URL you'll find your API URL, you can click `Copy` to copy it to the clipboard.
- Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`.
<video width="99%" muted playsInline controls="true">
<source
src="/docs/videos/api/api-url-and-key.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
## Configure your Services ID
- Under `Identifiers`, click on your newly-created Services ID.
- Check the box next to `Sign In With Apple` to enable it.
- Click `Configure` to the right.
- Make sure your newly created Bundle ID is selected under `Primary App ID`
- Add your domain to the `Domains and Subdomains` box (do not add `https://`, just add the domain).
- In the `Return URLs` box, type the callback URL of your app which you found in the previous step and click `Next` at the bottom right.
- Click `Done` at the bottom.
- Click `Continue` at the top right.
- Click `Save` at the top right.
## Download your secret key
Now you'll need to download a `secret key` file from Apple that will be used to generate your `client_secret`.
- Go to `Certificates, Identifiers & Profiles`.
- Click on `Keys` at the left.
- Click on the `+` sign in the upper left next to `Keys`.
- Enter a `Key Name`.
- Check `Sign In with Apple`.
- Click `Configure` to the right.
- Select your newly-created Services ID from the dropdown selector.
- Click `Save` at the top right.
- Click `Continue` at the top right.
- Click `Register` at the top right.
- Click `Download` at the top right.
- Save the downloaded file -- this contains your "secret key" that will be used to generate your `client_secret`.
- Click `Done` at the top right.
## Generate a `client_secret`
The `secret key` you downloaded is used to create the `client_secret` string you'll need to authenticate your users.
According to the [Apple Docs](https://developer.apple.com/documentation/signinwithapplerestapi/generate_and_validate_tokens) it needs to be a JWT
token encrypted using the Elliptic Curve Digital Signature Algorithm (ECDSA) with the P-256 curve and the SHA-256 hash algorithm.
At this time, the easiest way to generate this JWT token is with [Ruby](https://www.ruby-lang.org/en/).
If you don't have Ruby installed, you can [Download Ruby Here](https://www.ruby-lang.org/en/downloads).
- Install Ruby (or check to make sure it's installed on your system).
- Install [ruby-jwt](https://github.com/jwt/ruby-jwt).
- From the command line, run: `sudo gem install jwt`.
Create the script below using a text editor: `secret_gen.rb`
```ruby
require "jwt"
key_file = "Path to the private key"
team_id = "Your Team ID"
client_id = "The Service ID of the service you created"
key_id = "The Key ID of the private key"
validity_period = 180 # In days. Max 180 (6 months) according to Apple docs.
private_key = OpenSSL::PKey::EC.new IO.read key_file
token = JWT.encode(
{
iss: team_id,
iat: Time.now.to_i,
exp: Time.now.to_i + 86400 * validity_period,
aud: "https://appleid.apple.com",
sub: client_id
},
private_key,
"ES256",
header_fields=
{
kid: key_id
}
)
puts token
```
1. Edit the `secret_gen.rb` file:
- `key_file` = "Path to the private key you downloaded from Apple". It should look like this: `AuthKey_XXXXXXXXXX.p8`.
- `team_id` = "Your Team ID". This is found at the top right of the Apple Developer site (next to your name).
- `client_id` = "The Service ID of the service you created". This is the `Services ID` you created in the above step `Obtain a Services ID`. If you've lost this ID, you can find it in the Apple Developer Site:
- Go to `Certificates, Identifiers & Profiles`.
- Click `Identifiers` at the left.
- At the top right drop-down, select `Services IDs`.
- Find your Identifier in the list (i.e. app.com.acme.roadrunner).
- `key_id` = "The Key ID of the private key". This can be found in the name of your downloaded secret file (For a file named `AuthKey_XXXXXXXXXX.p8` your key_id is `XXXXXXXXXX`). If you've lost this ID, you can find it in the Apple Developer Site:
- Go to `Certificates, Identifiers & Profiles`.
- Click `Keys` at the left.
- Click on your newly-created key in the list.
- Look under `Key ID` to find your key_id.
2. From the command line, run: `ruby secret_gen.rb > client_secret.txt`.
3. Your `client_secret` is now stored in this `client_secret.txt` file.
## Add your OAuth credentials to Supabase
- Go to your [Supabase Dashboard](https://app.supabase.com).
- In the left sidebar, click the `Authentication` icon (near the top).
- Click `Settings` from the list to go to the `Authentication Settings` page.
- Enter the final (hosted) URL of your app under `Site URL` (this is important).
- Under `External OAuth Providers` turn `Apple Enabled` to ON.
- Enter your `client_id` and `client_secret` saved in the previous steps.
- Click `Save`.
## Add login code to your client app
When your user signs in, call [signInWithOAuth()](/docs/reference/javascript/auth-signinwithoauth) with `apple` as the `provider`:
```js
async function signInWithApple() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'apple',
})
}
```
When your user signs out, call [signOut()](/docs/reference/javascript/auth-signout) to remove them from the browser session and any objects from localStorage:
```js
async function signout() {
const { error } = await supabase.auth.signOut()
}
```
## Resources
- [Apple Developer Account](https://developer.apple.com).
- [Ruby](https://www.ruby-lang.org/en/) Docs.
- [ruby-jwt](https://github.com/jwt/ruby-jwt) library.
- Thanks to [Janak Amarasena](https://medium.com/@janakda) who did all the heavy lifting in [How to configure Sign In with Apple](https://medium.com/identity-beyond-borders/how-to-configure-sign-in-with-apple-77c61e336003).
@@ -1,98 +0,0 @@
---
id: auth-azure
title: 'Login with Azure'
description: Add Azure OAuth to your Supabase project
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
To enable Azure Auth for your project, you need to set up an Azure OAuth application and add the application credentials to your Supabase Dashboard.
## Overview
Azure OAuth consists of four broad steps:
- Create an application under Azure Active Directory.
- Obtain a `Application (client) ID` with “Sign In with Azure” capabilities. This will be used as the `client id`.
- Create a `Secret ID` with “Sign In with Azure” capabilities. The value of the secret will be used as the `client secret`.
- Add the callback url of your application to the allowlist.
## Access your Azure Developer account
- Go to [portal.azure.com](https://portal.azure.com/#home).
- Login and select "Azure Active Directory" under the list of Azure Services.
## Register an application
- Under Azure Active Directory, select "App registrations" in the side panel.
- Select "New registration".
- Choose a name and select your preferred option for the supported account types.
- Specify the "Redirect URI".
- The redirect / callback URI should look like this: `https://<project-ref>.supabase.co/auth/v1/callback`
- Click "Register" at the bottom of the form.
![Register an application.](/img/guides/auth-azure/azure-register-app.png)
## Obtain a Client ID
This will serve as the `client_id` when you make API calls to authenticate the user.
- Once your app has been registered, the client id can be found under the [list of app registrations](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps) under the column titled "Application (client) ID".
![Obtain the client id](/img/guides/auth-azure/azure-client-id.png)
## Obtain a Secret ID
This will serve as the `client_secret` when you make API calls to authenticate the user.
- Click on the name of the app registered above.
- Under "Essentials", click on "Client credentials".
- Navigate to the "Client secrets" tab and select "New client secret".
- Enter a description and choose your preferred expiry for the secret.
- Once the secret is generated, save the `value` (not the secret ID).
![Obtain the client secret](/img/guides/auth-azure/azure-client-secret.png)
## Obtain the Tenant URL
This will allow your users to use your custom Azure login page when logging in.
- Select the Directory (Tenant) ID value.
- The Azure Tenant URL should look like this: `https://login.microsoftonline.com/<tenant-id>`
![Obtain the tenant url](/img/guides/auth-azure/azure-tenant-url.png)
## Add login code to your client app
:::tip
Supabase Auth requires that Azure returns a valid email address. Therefore you must request the `email` scope in the `signIn` method above.
:::
When your user signs in, call [signInWithOAuth()](/docs/reference/javascript/auth-signinwithoauth) with `azure` as the `provider`:
```js
async function signInWithAzure() {
const { data, error } = await supabase.auth.signInWithOAuth(
{
provider: 'azure',
},
{
scopes: 'email',
}
)
}
```
When your user signs out, call [signOut()](/docs/reference/javascript/auth-signout) to remove them from the browser session and any objects from localStorage:
```js
async function signout() {
const { error } = await supabase.auth.signOut()
}
```
## Resources
- [Azure Developer Account](https://portal.azure.com)
- [GitHub Discussion](https://github.com/supabase/gotrue/pull/54#issuecomment-757043573)
@@ -1,97 +0,0 @@
---
id: auth-bitbucket
title: 'Login with Bitbucket'
description: Add Bitbucket OAuth to your Supabase project
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
To enable Bitbucket Auth for your project, you need to set up a BitBucket OAuth application and add the application credentials to your Supabase Dashboard.
## Overview
Setting up Bitbucket logins for your application consists of 3 parts:
- Create and configure a Bitbucket OAuth Consumer on [Bitbucket](https://bitbucket.org)
- Add your Bitbucket OAuth Consumer keys to your [Supabase Project](https://app.supabase.com)
- Add the login code to your [Supabase JS Client App](https://github.com/supabase/supabase-js)
## Access your Bitbucket account
- Go to [bitbucket.org](https://bitbucket.org/).
- Click on `Login` at the top right to log in.
![Bitbucket Developer Portal.](/img/guides/auth-bitbucket/bitbucket-portal.png)
## Find your callback URL
The next step requires a callback URL, which looks like this:
`https://<project-ref>.supabase.co/auth/v1/callback`
- Go to your [Supabase Project Dashboard](https://app.supabase.com).
- Click on the `Settings` icon at the bottom of the left sidebar.
- Click on `API` in the list.
- Under Config / URL you'll find your API URL, you can click `Copy` to copy it to the clipboard.
- Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`.
<video width="99%" muted playsInline controls="true">
<source
src="/docs/videos/api/api-url-and-key.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
## Create a Bitbucket OAuth app
- Click on your profile icon at the bottom left
- Click on `All Workspaces`
- Select a workspace and click on it to select it
- Click on `Settings` on the left
- Click on `OAuth consumers` on the left under `Apps and Features` (near the bottom)
- Click `Add Consumer` at the top
- Enter the name of your app under `Name`
- In `Callback URL`, type the callback URL of your app
- Check the permissions you need (Email, Read should be enough)
- Click `Save` at the bottom
- Click on your app name (the name of your new OAuth Consumer)
- Copy your `Key` (`client_key`) and `Secret` (`client_secret`) codes
## Add your Bitbucket credentials into your Supabase Project
- Go to your [Supabase Project Dashboard](https://app.supabase.com)
- In the left sidebar, click the `Authentication` icon (near the top)
- Click `Settings` from the list to go to the `Authentication Settings` page
- Enter the final (hosted) URL of your app under `Site URL` (this is important)
- Under `External OAuth Providers` turn `Bitbucket Enabled` to ON
- Enter your `client_id` and `client_secret` saved in the previous step
- Click `Save`
## Add login code to your client app
When your user signs in, call [signInWithOAuth()](/docs/reference/javascript/auth-signinwithoauth) with `bitbucket` as the `provider`:
```js
async function signInWithBitbucket() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'bitbucket',
})
}
```
When your user signs out, call [signOut()](/docs/reference/javascript/auth-signout) to remove them from the browser session and any objects from localStorage:
```js
async function signout() {
const { error } = await supabase.auth.signOut()
}
```
## Resources
- [Supabase Account - Free Tier OK](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Bitbucket Account](https://bitbucket.org)
@@ -1,113 +0,0 @@
---
id: auth-captcha
title: 'Enable Captcha Protection'
description: Add Captcha Protection to your Supabase project
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
# hCaptcha guide
Supabase provides you with the option of adding captcha to your sign-in, sign-up, and password reset forms. This keeps your website safe from bots and malicious scripts. Supabase authentication has support for [hCaptcha](https://www.hcaptcha.com/).
### Sign up for hCaptcha
Go to the [hCaptcha](https://www.hcaptcha.com/) website and sign up for an account. On the welcome page, copy the **Sitekey** and **Secret key**.
If you have already signed up and didn't copy this information from the welcome page, you can get the **Secret key** from the settings page.
![site_secret_settings.png](/img/guides/auth-captcha/site_secret_settings.png)
The **Sitekey** can be found in the **Settings** of the active site you created.
![sites_dashboard.png](/img/guides/auth-captcha/sites_dashboard.png)
In the Settings page, look for the **Sitekey** section and copy the key.
![sitekey_settings.png](/img/guides/auth-captcha/sitekey_settings.png)
### Enable hCaptcha protection for your Supabase project
Navigate to the **[Authentication](https://app.supabase.com/project/_/auth/settings)** page in the Supabase Dashboard and find the **Enable hCaptcha protection** toggle under the **Security and Protection** section.
![supabase_auth_general_settings.png](/img/guides/auth-captcha/supabase_auth_general_settings.png)
Enter your hCaptcha **Secret key** and click **Save**.
### Add the hCaptcha frontend component
The frontend requires some changes to provide the captcha on-screen for the user. This example uses React and the hCaptcha React component, but hCaptcha can be used with any JavaScript framework.
Install `@hcaptcha/react-hcaptcha` in your project as a dependency.
```bash
npm install @hcaptcha/react-hcaptcha
```
Now import the `HCaptcha` component from the `@hcaptcha/react-hcaptcha` library.
```javascript
import HCaptcha from '@hcaptcha/react-hcaptcha'
```
Let’s create a empty state to store our `captchaToken`
```jsx
const [captchaToken, setCaptchaToken] = useState()
```
Now lets add the HCaptcha component to the JSX section of our code
```html
<HCaptcha />
```
We will pass it the sitekey we copied from the hCaptcha website as a property along with a onVerify property which takes a callback function. This callback function will have a token as one of its properties. Let's set the token in the state using `setCaptchaToken`
```jsx
<HCaptcha
sitekey="your-sitekey"
  onVerify={(token) => { setCaptchaToken(token) }
/>
```
Now lets use the captcha token we receive in our Supabase signUp function.
```jsx
await supabase.auth.signUp({
email,
password,
options: { captchaToken },
})
```
We will also need to reset the captcha challenge after we have made a call to the function above.
Create a ref to use on our HCaptcha component.
```jsx
const captcha = useRef()
```
Let's add a ref attribute on the `HCaptcha` component and assign the `captcha` constant to it.
```jsx
<HCaptcha
ref={captcha}
sitekey="your-sitekey"
onVerify={(token) => {
setCaptchaToken(token)
}}
/>
```
Reset the `captcha` after the signUp function is called using the following code:
```jsx
captcha.current.resetCaptcha()
```
In order to test that this works locally we will need to use something like [ngrok](https://ngrok.com/) or add an entry to your hosts file. You can read more about this in the [hCaptcha docs](https://docs.hcaptcha.com/#local-development).
Run the application and you should now be provided with a captcha challenge.
@@ -1,99 +0,0 @@
---
id: auth-discord
title: 'Login with Discord'
description: Add Discord OAuth to your Supabase project
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
To enable Discord Auth for your project, you need to set up a Discord Application and add the Application OAuth credentials to your Supabase Dashboard.
## Overview
Setting up Discord logins for your application consists of 3 parts:
- Create and configure a Discord Application [Discord Developer Portal](https://discord.com/developers)
- Add your Discord OAuth Consumer keys to your [Supabase Project](https://app.supabase.com)
- Add the login code to your [Supabase JS Client App](https://github.com/supabase/supabase-js)
## Access your Discord account
- Go to [discord.com](https://discord.com/).
- Click on `Login` at the top right to log in.
![Discord Portal.](/img/guides/auth-discord/discord-portal.png)
- Once logged in, go to [discord.com/developers](https://discord.com/developers).
![Discord Portal.](/img/guides/auth-discord/discord-developer-portal.png)
## Find your callback URL
In the next step you require a callback URL, which looks like this:
`https://<project-ref>.supabase.co/auth/v1/callback`
- Go to your [Supabase Project Dashboard](https://app.supabase.com).
- Click on the `Settings` icon at the bottom of the left sidebar.
- Click on `API` in the list.
- Under Config / URL you'll find your API URL, you can click `Copy` to copy it to the clipboard.
- Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`.
<video width="99%" muted playsInline controls="true">
<source
src="/docs/videos/api/api-url-and-key.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
## Create a Discord Application
- Click on `New Application` at the top right.
- Enter the name of your application and click `Create`.
- Click on `OAuth2` under `Settings` in the left side panel.
- Click `Add Redirect` under `Redirects`.
- Type or paste your `callback URL` into the `Redirects` box.
- Click `Save Changes` at the bottom.
- Copy your `Client ID` and `Client Secret` under `Client information`.
## Add your Discord credentials into your Supabase Project
- Go to your [Supabase Project Dashboard](https://app.supabase.com)
- In the left sidebar, click the `Authentication` icon (near the top)
- Click `Settings` from the list to go to the `Authentication Settings` page
- Enter the final (hosted) URL of your app under `Site URL` (this is important)
- Under `External OAuth Providers` turn `Discord Enabled` to ON
- Enter your `client_id` and `client_secret` saved in the previous step
- Click `Save`
## Add login code to your client app
When your user signs in, call [signInWithOAuth()](/docs/reference/javascript/auth-signinwithoauth) with `discord` as the `provider`:
```js
async function signInWithDiscord() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'discord',
})
}
```
If your user is already signed in, Discord prompts the user again for authorization.
When your user signs out, call [signOut()](/docs/reference/javascript/auth-signout) to remove them from the browser session and any objects from localStorage:
```js
async function signout() {
const { error } = await supabase.auth.signOut()
}
```
## Resources
- [Supabase Account - Free Tier OK](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Discord Account](https://discord.com)
- [Discord Developer Portal](https://discord.com/developers)
@@ -1,106 +0,0 @@
---
id: auth-email
title: 'Login With Email'
description: Use Supabase to Authenticate and Authorize your users using email.
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
## Overview
Setting up Email logins for your Supabase application.
- Add Email authenticator to your [Supabase Project](https://app.supabase.com)
- Add the login code to your application - [JavaScript](https://github.com/supabase/supabase-js) | [Flutter](https://github.com/supabase/supabase-flutter)
## Configure email settings
1. Go to the [Authentication Settings](https://app.supabase.com/project/_/auth/settings) page in the Dashboard.
1. For **Site URL**, enter the final (hosted) URL of your app.
1. Under Auth Providers, **enable email provider**.
:::note Self hosting
For self-hosting, you can update your project configuration using the files and environment variables provided.
See the [self-hosting docs](/docs/guides/hosting/overview#configuration) for details.
:::
## Add login code to your client app
<Tabs
defaultValue="js"
groupId="guides/auth"
values={[{ label: 'JavaScript', value: 'js' }, { label: 'Dart', value: 'dart' }]}
>
<TabItem value="js">
When your user signs in, call [signInWithPassword()](/docs/reference/javascript/auth-signinwithpassword) with their email address and password:
```js
async function signInWithEmail() {
const { data, error } = await supabase.auth.signInWithPassword({
email: 'example@email.com',
password: 'example-password',
})
}
```
</TabItem>
<TabItem value="dart">
When your user signs in, call [signInWithPassword()](/docs/reference/dart/auth-signinwithpassword) with their email address and password:
```dart
Future<void> signInWithEmail() async {
final AuthResponse res = await supabase.auth.signInWithPassword(
email: 'example@email.com',
password: 'example-password'
);
}
```
</TabItem>
</Tabs>
<Tabs
defaultValue="js"
groupId="guides/auth"
values={[{ label: 'JavaScript', value: 'js' }, { label: 'Dart', value: 'dart' }]}
>
<TabItem value="js">
When your user signs out, call [signOut()](/docs/reference/javascript/auth-signout) to remove them from the browser session and any objects from localStorage:
```js
async function signOut() {
const { error } = await supabase.auth.signOut()
}
```
</TabItem>
<TabItem value="dart">
When your user signs out, call [signOut()](/docs/reference/dart/auth-signout) to remove them from the browser session and any objects from localStorage:
```dart
Future<void> signOut() async {
await supabase.auth.signOut();
}
```
</TabItem>
</Tabs>
## Resources
- [Supabase Account - Free Tier OK](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Supabase Flutter Client](https://github.com/supabase/supabase-flutter)
@@ -1,114 +0,0 @@
---
id: auth-facebook
title: 'Login with Facebook'
description: Add Facebook OAuth to your Supabase project
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
To enable Facebook Auth for your project, you need to set up a Facebook OAuth application and add the application credentials to your Supabase Dashboard.
## Overview
Setting up Facebook logins for your application consists of 3 parts:
- Create and configure a Facebook Application on the [Facebook Developers Site](https://developers.facebook.com)
- Add your Facebook keys to your [Supabase Project](https://app.supabase.com)
- Add the login code to your [Supabase JS Client App](https://github.com/supabase/supabase-js)
## Access your Facebook Developer account
- Go to [developers.facebook.com](https://developers.facebook.com).
- Click on `Log In` at the top right to log in.
![Facebook Developer Portal.](/img/guides/auth-facebook/facebook-portal.png)
## Create a Facebook App
- Click on `My Apps` at the top right.
- Click `Create App` near the top right.
- Select your app type and click `Continue`.
- Fill in your app information, then click `Create App`.
- This should bring you to the screen: `Add Products to Your App`. (Alternatively you can click on `Add Product` in the left sidebar to get to this screen.)
## Find your callback URI
The next step requires a callback URI, which looks like this:
`https://<project-ref>.supabase.co/auth/v1/callback`
- Go to your [Supabase Project Dashboard](https://app.supabase.com).
- Click on the `Settings` icon at the bottom of the left sidebar.
- Click on `API` in the list.
- Under Config / URL you'll find your API URL, you can click `Copy` to copy it to the clipboard.
- Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`.
<video width="99%" muted playsInline controls="true">
<source
src="/docs/videos/api/api-url-and-key.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
## Set up FaceBook Login for your Facebook App
From the `Add Products to your App` screen:
- Click `Setup` under `Facebook Login`
- Skip the Quickstart screen, instead, in the left sidebar, click `Settings` under `Facebook Login`
- Enter your callback URI under `Valid OAuth Redirect URIs` on the `Facebook Login Settings` page
- Enter this in the `Valid OAuth Redirect URIs` box
- Click `Save Changes` at the bottom right
Be aware that you have to set the right access levels on your Facebook App to enable 3rd party applications to read the email address.
From the `App Review -> Permissions and Features` screen:
- Click the button `Request Advanced Access` on the right side of `public_profile` and `email`
You can read more about access levels [here](https://developers.facebook.com/docs/graph-api/overview/access-levels/)
## Copy your Facebook App ID and Secret
- Click `Settings / Basic` in the left sidebar
- Copy your App ID from the top of the `Basic Settings` page
- Under `App Secret` click `Show` then copy your secret
- Make sure all required fields are completed on this screen.
## Enter your Facebook App ID and Secret into your Supabase Project
- Go to your [Supabase Project Dashboard](https://app.supabase.com)
- In the left sidebar, click the `Authentication` icon (near the top)
- Click `Settings` from the list to go to the `Authentication Settings` page
- Enter the final (hosted) URL of your app under `Site URL` (this is important)
- Under `External OAuth Providers` turn `Facebook Enabled` to ON
- Enter your `Facebook client ID` and `Facebook secret` saved in the previous step
- Click `Save`
## Add login code to your client app
When your user signs in, call [signInWithOAuth()](/docs/reference/javascript/auth-signinwithoauth) with `facebook` as the `provider`:
```js
async function signInWithFacebook() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'facebook',
})
}
```
When your user signs out, call [signOut()](/docs/reference/javascript/auth-signout) to remove them from the browser session and any objects from localStorage:
```js
async function signout() {
const { error } = await supabase.auth.signOut()
}
```
## Resources
- [Supabase Account - Free Tier OK](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Facebook Developers Dashboard](https://developers.facebook.com/)
@@ -1,107 +0,0 @@
---
id: auth-github
title: 'Login with GitHub'
description: Add GitHub OAuth to your Supabase project
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
To enable GitHub Auth for your project, you need to set up a GitHub OAuth application and add the application credentials to your Supabase Dashboard.
## Overview
Setting up GitHub logins for your application consists of 3 parts:
- Create and configure a GitHub OAuth App on [GitHub](https://github.com)
- Add your GitHub OAuth keys to your [Supabase Project](https://app.supabase.com)
- Add the login code to your [Supabase JS Client App](https://github.com/supabase/supabase-js)
## Access your GitHub account
- Go to [github.com](https://github.com).
- Click on `Sign In` at the top right to log in.
![GitHub Developer Portal.](/img/guides/auth-github/github-portal.png)
## Create a GitHub Oauth App
Go to the [GitHub Developer Settings](https://github.com/settings/developers) page:
- Click on your profile photo at the top right
- Click Settings near the bottom of the menu
- In the left sidebar, click `Developer settings` (near the bottom)
- In the left sidebar, click `OAuth Apps`
## Find your callback URL
The next step requires a callback URL, which looks like this:
`https://<project-ref>.supabase.co/auth/v1/callback`
- Go to your [Supabase Project Dashboard](https://app.supabase.com).
- Click on the `Settings` icon at the bottom of the left sidebar.
- Click on `API` in the list.
- Under Config / URL you'll find your API URL, you can click `Copy` to copy it to the clipboard.
- Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`.
<video width="99%" muted playsInline controls="true">
<source
src="/docs/videos/api/api-url-and-key.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
## Register a new OAuth application
- Click `Register a new application`. If you've created an app before, click `New OAuth App` here.
- In `Application name`, type the name of your app.
- In `Homepage URL`, type the full URL to your app's website.
- In `Authorization callback URL`, type the callback URL of your app.
- Enter the URL in the `Valid OAuth Redirect URIs` box.
- Click `Save Changes` at the bottom right.
- Click `Register Application`.
Copy your new OAuth credentials
- Copy and save your `Client ID`.
- Click `Generate a new client secret`.
- Copy and save your `Client secret`.
## Enter your GitHub credentials into your Supabase Project
- Go to your [Supabase Project Dashboard](https://app.supabase.com)
- In the left sidebar, click the `Authentication` icon (near the top)
- Click `Settings` from the list to go to the `Authentication Settings` page
- Enter the final (hosted) URL of your app under `Site URL` (this is important)
- Under `External OAuth Providers` turn `GitHub Enabled` to ON
- Enter your `GitHub Client ID` and `GitHub Client Secret` saved in the previous step
- Click `Save`
## Add login code to your client app
When your user signs in, call [signInWithOAuth()](/docs/reference/javascript/auth-signinwithoauth) with `github` as the `provider`:
```js
async function signInWithGitHub() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'github',
})
}
```
When your user signs out, call [signOut()](/docs/reference/javascript/auth-signout) to remove them from the browser session and any objects from localStorage:
```js
async function signout() {
const { error } = await supabase.auth.signOut()
}
```
## Resources
- [Supabase Account - Free Tier OK](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [GitHub Developer Settings](https://github.com/settings/developers)
@@ -1,94 +0,0 @@
---
id: auth-gitlab
title: 'Login with GitLab'
description: Add GitLab OAuth to your Supabase project
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
To enable GitLab Auth for your project, you need to set up a GitLab OAuth application and add the application credentials to your Supabase Dashboard.
## Overview
Setting up GitLab logins for your application consists of 3 parts:
- Create and configure a GitLab Application on [GitLab](https://gitlab.com)
- Add your GitLab Application keys to your [Supabase Project](https://app.supabase.com)
- Add the login code to your [Supabase JS Client App](https://github.com/supabase/supabase-js)
## Access your GitLab account
- Go to [gitlab.com](https://gitlab.com).
- Click on `Login` at the top right to log in.
![GitLab Developer Portal.](/img/guides/auth-gitlab/gitlab-portal.png)
## Find your callback URL
The next step requires a callback URL, which looks like this:
`https://<project-ref>.supabase.co/auth/v1/callback`
- Go to your [Supabase Project Dashboard](https://app.supabase.com).
- Click on the `Settings` icon at the bottom of the left sidebar.
- Click on `API` in the list.
- Under Config / URL you'll find your API URL, you can click `Copy` to copy it to the clipboard.
- Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`.
<video width="99%" muted playsInline controls="true">
<source
src="/docs/videos/api/api-url-and-key.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
## Create your GitLab Application
- Click on your `profile logo` (avatar) in the top-right corner.
- Select `Edit profile`.
- In the left sidebar, select Applications.
- Enter the name of the application.
- In the `Redirect URI` box, type the callback URL of your app.
- Check the box next to `Confidential` (make sure it is checked).
- Check the scope named `read_user` (this is the only required scope).
- Click `Save Application` at the bottom.
- Copy and save your `Application ID` (`client_id`) and `Secret` (`client_secret`) which you'll need later.
## Add your GitLab credentials into your Supabase Project
- Go to your [Supabase Project Dashboard](https://app.supabase.com).
- In the left sidebar, click the `Authentication` icon (near the top).
- Click `Settings` from the list to go to the `Authentication Settings` page.
- Enter the final (hosted) URL of your app under `Site URL` (this is important).
- Under `External OAuth Providers` turn `GitLab Enabled` to ON.
- Enter your `client_id` and `client_secret` saved in the previous step.
- Click `Save`.
## Add login code to your client app
When your user signs in, call [signInWithOAuth()](/docs/reference/javascript/auth-signinwithoauth) with `gitlab` as the `provider`:
```js
async function signInWithGitLab() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'gitlab',
})
}
```
When your user signs out, call [signOut()](/docs/reference/javascript/auth-signout) to remove them from the browser session and any objects from localStorage:
```js
async function signout() {
const { error } = await supabase.auth.signOut()
}
```
## Resources
- [Supabase Account - Free Tier OK](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [GitLab Account](https://gitlab.com)
@@ -1,122 +0,0 @@
---
id: auth-google
title: 'Login with Google'
description: Add Google OAuth to your Supabase project
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
To enable Google Auth for your project, you need to set up a Google OAuth application and add the application credentials to your Supabase Dashboard.
## Overview
Setting up Google logins for your application consists of 3 parts:
- Create and configure a Google Project on the [Google Cloud Platform Console](https://console.cloud.google.com/home/dashboard)
- Add your Google OAuth keys to your [Supabase Project](https://app.supabase.com)
- Add the login code to your [Supabase JS Client App](https://github.com/supabase/supabase-js)
## Access your Google Cloud Platform account
- Go to [cloud.google.com](https://cloud.google.com).
- Click on `Sign in` at the top right to log in.
![Google Developer Portal.](/img/guides/auth-google/google-portal.png)
## Create a Google Cloud Platform Project
- Click on `Select a Project` at the top left.
- (Or, if a project is currently selected, click on the current project name at the top left.)
- Click `New Project` at the top right.
- Fill in your app information, then click `Create`.
- (This can take a few minutes.)
- This should bring you to the dashboard for your new project.
## Create the OAuth Keys for your project
From your project's dashboard screen:
- In the search bar at the top labeled `Search products and resources` type `OAuth`.
- Click on `OAuth consent screen` from the list of results.
- On the `OAuth consent screen` page select `External`.
- Click `Create`.
## Edit your app information
- On the `Edit app registration` page fill out your app information.
- Click `Save and continue` at the bottom.
## Find your callback URL
The next step requires a callback URL, which looks like this:
`https://<project-ref>.supabase.co/auth/v1/callback`
- Go to your [Supabase Project Dashboard](https://app.supabase.com).
- Click on the `Settings` icon at the bottom of the left sidebar.
- Click on `API` in the list.
- Under Config / URL you'll find your API URL, you can click `Copy` to copy it to the clipboard.
- Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`.
<video width="99%" muted playsInline controls="true">
<source
src="/docs/videos/api/api-url-and-key.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
## Create your Google credentials
- Click `Credentials` at the left to go to the `Credentials` page on the Google Cloud Platform console.
- Click `Create Credentials` near the top then select `OAuth client ID`
- On the `Create OAuth client ID` page, select your application type. If you're not sure, choose `Web application`.
- Fill in your app name.
- At the bottom, under `Authorized redirect URIs` click `Add URI`.
- Enter your callback URI under `Authorized redirect URIs` at the bottom.
- Enter your callback URI in the `Valid OAuth Redirect URIs` box.
- Click `Save Changes` at the bottom right.
- Click `Create`.
Copy your new OAuth credentials
- A box will appear called `OAuth client created`.
- Copy and save the values under `Your Client ID` and `Your Client Secret`.
## Enter your Google credentials into your Supabase Project
- Go to your [Supabase Project Dashboard](https://app.supabase.com)
- In the left sidebar, click the `Authentication` icon (near the top)
- Click `Settings` from the list to go to the `Authentication Settings` page
- Enter the final (hosted) URL of your app under `Site URL` (this is important)
- Under `External OAuth Providers` turn `Google Enabled` to ON
- Enter your `Google Client ID` and `Google Client Secret` saved in the previous step
- Click `Save`
## Add login code to your client app
When your user signs in, call [signInWithOAuth()](/docs/reference/javascript/auth-signinwithoauth) with `google` as the `provider`:
```js
async function signInWithGoogle() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
})
}
```
When your user signs out, call [signOut()](/docs/reference/javascript/auth-signout) to remove them from the browser session and any objects from localStorage:
```js
async function signout() {
const { error } = await supabase.auth.signOut()
}
```
## Resources
- [Supabase Account - Free Tier OK](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Google Cloud Platform Console](https://console.cloud.google.com/home/dashboard)
@@ -1,297 +0,0 @@
---
id: auth-ui
title: Auth UI
description: A prebuilt, customizable React component for authenticating users.
---
Auth UI is a pre-built React component for authenticating users.
It supports custom themes and extensible styles to match your brand and aesthetic.
<video width="99%" muted playsInline controls="true">
<source
src="https://supabase.com/images/blog/lw5-one-more/auth-ui-demo.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
## Set up Auth UI
Install the latest version of [supabase-js](/docs/reference/javascript) and the Auth UI package:
```bash
npm install @supabase/supabase-js @supabase/auth-ui-react
```
### Import the Auth component
Pass `supabaseClient` from `@supabase/supabase-js` as a prop to the component.
```js title="/src/index.js"
import { createClient } from '@supabase/supabase-js'
import { Auth } from '@supabase/auth-ui-react'
const supabase = createClient(
'<INSERT PROJECT URL>',
'<INSERT PROJECT ANON API KEY>'
)
const App = () => <Auth supabaseClient={supabase} />
```
This renders the Auth component without any styling.
We recommend using one of the predefined themes to style the UI.
Import the theme you want to use and pass it to the `appearence.theme` prop.
```diff js title="/src/index.js"
import {
Auth,
// highlight-next-line
ThemeSupa
} from '@supabase/auth-ui-react'
const App = () => (
<Auth
supabaseClient={supabase}
// highlight-next-line
appearance={{ theme: ThemeSupa }}
/>
)
```
## Customization
There are several ways to customize Auth UI:
- Use one of the [predefined themes](#predefined-themes) that comes with Auth UI
- Extend a theme by [overriding the variable tokens](#override-themes) in a theme
- [Create your own theme](#create-theme)
- [Use your own CSS classes](#custom-css-classes)
- [Use inline styles](#custom-inline-styles)
- [Use your own labels](#custom-labels)
### Predefined themes
Auth UI comes with several themes to customize the appearance. Each predefined theme comes with at least two variations, a `default` variation, and a `dark` variation. You can switch between these themes using the `theme` prop. Import the theme you want to use and pass it to the `appearence.theme` prop.
```js title="/src/index.js"
import { createClient } from '@supabase/supabase-js'
//highlight-next-line
import { Auth, ThemeSupa } from '@supabase/auth-ui-react'
const supabase = createClient(
'<INSERT PROJECT URL>',
'<INSERT PROJECT ANON API KEY>'
)
const App = () => (
<Auth
supabaseClient={supabase}
// highlight-next-line
appearance={{ theme: ThemeSupa }}
/>
)
```
:::info
Currently there is only one predefined theme available, but we plan to add more.
:::
### Switch theme variations
Auth UI comes with two theme variations: `default` and `dark`. You can switch between these themes with the `theme` prop.
```js title="/src/index.js"
import { createClient } from '@supabase/supabase-js'
import { Auth, ThemeSupa } from '@supabase/auth-ui-react'
const supabase = createClient(
'<INSERT PROJECT URL>',
'<INSERT PROJECT ANON API KEY>'
)
const App = () => (
<Auth
supabaseClient={supabase}
appearance={{ theme: ThemeSupa }}
// highlight-next-line
theme="dark"
/>
)
```
If you don't pass a value to `theme` it uses the `"default"` theme. You can pass `"dark"` to the theme prop to switch to the `dark` theme. If your theme has other variations, use the name of the variation in this prop.
### Override themes
Auth UI themes can be overridden using variable tokens. See the [list of variable tokens](https://github.com/supabase-community/auth-ui/blob/main/packages/react/common/theming/Themes.tsx).
```js title="/src/index.js"
import { createClient } from '@supabase/supabase-js'
import { Auth, ThemeSupa } from '@supabase/auth-ui-react'
const supabase = createClient(
'<INSERT PROJECT URL>',
'<INSERT PROJECT ANON API KEY>'
)
const App = () => (
<Auth
supabaseClient={supabase}
appearance={{
theme: ThemeSupa,
// highlight-start
variables: {
default: {
colors: {
brand: 'red',
brandAccent: 'darkred',
},
},
},
// highlight-end
}}
/>
)
```
If you created your own theme, you may not need to override any of the them.
### Create your own theme {#create-theme}
You can create your own theme by following the same structure within a `appearance.theme` property.
See the list of [tokens within a theme](https://github.com/supabase-community/auth-ui/blob/main/packages/react/common/theming/Themes.tsx).
```js title="/src/index.js"
import { createClient } from '@supabase/supabase-js'
import { Auth } from '@supabase/auth-ui-react'
const supabase = createClient(
'<INSERT PROJECT URL>',
'<INSERT PROJECT ANON API KEY>'
)
const customTheme = {
default: {
colors: {
brand: 'hsl(153 60.0% 53.0%)',
brandAccent: 'hsl(154 54.8% 45.1%)',
brandButtonText: 'white',
// ..
},
dark: {
colors: {
brandButtonText: 'white',
defaultButtonBackground: '#2e2e2e',
defaultButtonBackgroundHover: '#3e3e3e',
//..
},
},
// You can also add more theme variations with different names.
evenDarker: {
colors: {
brandButtonText: 'white',
defaultButtonBackground: '#1e1e1e',
defaultButtonBackgroundHover: '#2e2e2e',
//..
},
},
}
const App = () => (
<Auth
supabaseClient={supabase}
theme="default" // can also be "dark" or "evenDarker"
appearance={{ theme: customTheme}}
/>
)
```
You can swich between different variations of your theme with the ["theme" prop](#switch-theme-variations).
### Custom CSS classes {#custom-css-classes}
You can use custom CSS classes for the following elements:
`"button"`, `"container"`, `"anchor"`, `"divider"`, `"label"`, `"input"`, `"loader"`, `"message"`.
```js title="/src/index.js"
import { createClient } from '@supabase/supabase-js'
import { Auth } from '@supabase/auth-ui-react'
const supabase = createClient(
'<INSERT PROJECT URL>',
'<INSERT PROJECT ANON API KEY>'
)
const App = () => (
<Auth
supabaseClient={supabase}
appearance={{
className: {
anchor: 'my-awesome-anchor',
button: 'my-awesome-button',
//..
},
}}
/>
)
```
### Custom inline CSS {#custom-inline-styles}
You can use custom CSS inline styles for the following elements:
`"button"`, `"container"`, `"anchor"`, `"divider"`, `"label"`, `"input"`, `"loader"`, `"message"`.
```js title="/src/index.js"
import { createClient } from '@supabase/supabase-js'
import { Auth } from '@supabase/auth-ui-react'
const supabase = createClient(
'<INSERT PROJECT URL>',
'<INSERT PROJECT ANON API KEY>'
)
const App = () => (
<Auth
supabaseClient={supabase}
appearance={{
style: {
button: { background: 'red', color: 'white' },
anchor: { color: 'blue' },
//..
},
}}
/>
)
```
### Custom labels {#custom-labels}
You can use custom labels with `localization.variables`. See the [list of labels](https://github.com/supabase-community/auth-ui/blob/main/packages/react/common/lib/Localization/en.json) that can be overwritten.
```js title="/src/index.js"
import { createClient } from '@supabase/supabase-js'
import { Auth } from '@supabase/auth-ui-react'
const supabase = createClient(
'<INSERT PROJECT URL>',
'<INSERT PROJECT ANON API KEY>'
)
const App = () => (
<Auth
supabaseClient={supabase}
//highlight-start
localization={{
variables: {
sign_in: {
email_label: 'Your email address',
password_label: 'Your strong password',
},
},
}}
//highlight-end
/>
)
```
@@ -1,71 +0,0 @@
---
id: index
title: Auth Helpers
description: A collection of framework-specific Auth utilities for working with Supabase.
sidebar_label: Overview
---
import useBaseUrl from '@docusaurus/useBaseUrl'
import ButtonCard from '@site/src/components/ButtonCard'
A collection of framework-specific Auth utilities for working with Supabase.
<div class="container" style={{ padding: 0 }}>
<div class="row is-multiline">
{/* Auth UI */}
<div class="col col--4">
<ButtonCard
class="card"
to={useBaseUrl('/guides/auth/auth-helpers/auth-ui')}
title={'Auth UI'}
description={'A pre-built React component for authenticating users.'}
style={{ height: '100%' }}
/>
</div>
{/* Next.js */}
<div class="col col--4">
<ButtonCard
class="card"
to={useBaseUrl('/guides/auth/auth-helpers/nextjs')}
title={'Next.js'}
description={
'Helpers for authenticating users in Next.js applications.'
}
style={{ height: '100%' }}
/>
</div>
{/* SvelteKit */}
<div class="col col--4">
<ButtonCard
class="card"
to={useBaseUrl('/guides/auth/auth-helpers/sveltekit')}
title={'SvelteKit'}
description={
'Helpers for authenticating users in SvelteKit applications.'
}
style={{ height: '100%' }}
/>
</div>
{/* Remix */}
<div class="col col--4">
<ButtonCard
class="card"
to={useBaseUrl('/guides/auth/auth-helpers/remix')}
title={'Remix'}
description={
'Helpers for authenticating users in Remix applications.'
}
style={{ height: '100%' }}
/>
</div>
</div>
</div>
## Status
The Auth Helpers are in `beta`. They are usable in their current state, but it's likely that there will be breaking changes.
## Additional Links
- [Source code](https://github.com/supabase/auth-helpers)
- [Known bugs and issues](https://github.com/supabase/auth-helpers/issues)
@@ -1,867 +0,0 @@
---
id: nextjs
title: Supabase Auth with Next.js
description: Authentication helpers for Next.js API routes, middleware, and SSR.
sidebar_label: 'Next.js'
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
This submodule provides convenience helpers for implementing user authentication in Next.js applications.
## Install the Next.js helper library
<Tabs
groupId="install"
defaultValue="npm"
values={[
{label: 'npm', value: 'npm'},
{label: 'Yarn', value: 'yarn'},
]}>
<TabItem value="npm">
```sh
npm install @supabase/auth-helpers-nextjs
```
This library supports the following tooling versions:
- Node.js: `^10.13.0 || >=12.0.0`
- Next.js: `>=10`
- Note: Next.js 13 is supported except for the new `app` directory approach. We're working on adding support for this and you can follow along [here](https://github.com/supabase/auth-helpers/issues/341).
Additionally, install the **React Auth Helpers** for components and hooks that can be used across all React-based frameworks.
```sh
npm install @supabase/auth-helpers-react
```
</TabItem>
<TabItem value="yarn">
```sh
yarn add @supabase/auth-helpers-nextjs
```
This library supports the following tooling versions:
- Node.js: `^10.13.0 || >=12.0.0`
- Next.js: `>=10`
- Note: Next.js 13 is supported except for the new `app` directory approach. We're working on adding support for this and you can follow along [here](https://github.com/supabase/auth-helpers/issues/341).
Additionally, install the **React Auth Helpers** for components and hooks that can be used across all React-based frameworks.
```sh
yarn add @supabase/auth-helpers-react
```
</TabItem>
</Tabs>
## Set up environment variables
Retrieve your project URL and anon key in your project's [API settings](https://app.supabase.com/project/_/settings/api) in the Dashboard to set up the following environment variables. For local development you can set them in a `.env.local` file. See an [example](https://github.com/supabase/auth-helpers/blob/main/examples/nextjs/.env.local.example).
```bash title=".env.local"
NEXT_PUBLIC_SUPABASE_URL=YOUR_SUPABASE_URL
NEXT_PUBLIC_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
```
## Basic Setup
<Tabs
groupId="language"
defaultValue="js"
values={[
{label: 'JavaScript', value: 'js'},
{label: 'TypeScript', value: 'ts'},
]}>
<TabItem value="js">
Wrap your `pages/_app.js` component with the `SessionContextProvider` component:
```jsx title="pages/_app.js"
import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs'
import { SessionContextProvider } from '@supabase/auth-helpers-react'
function MyApp({ Component, pageProps }) {
const router = useRouter()
// Create a new supabase browser client on every first render.
const [supabaseClient] = useState(() => createBrowserSupabaseClient())
return (
<SessionContextProvider
supabaseClient={supabaseClient}
initialSession={pageProps.initialSession}
>
<Component {...pageProps} />
</SessionContextProvider>
)
}
```
</TabItem>
<TabItem value="ts">
Wrap your `pages/_app.tsx` component with the `SessionContextProvider` component:
```tsx title="pages/_app.tsx"
import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs'
// highlight-next-line
import { SessionContextProvider, Session } from '@supabase/auth-helpers-react'
function MyApp({
Component,
pageProps,
}: AppProps<{
// highlight-next-line
initialSession: Session
}>) {
// Create a new supabase browser client on every first render.
const [supabaseClient] = useState(() => createBrowserSupabaseClient())
return (
<SessionContextProvider
supabaseClient={supabaseClient}
initialSession={pageProps.initialSession}
>
<Component {...pageProps} />
</SessionContextProvider>
)
}
```
</TabItem>
</Tabs>
You can now determine if a user is authenticated by checking that the `user` object returned by the `useUser()` hook is defined.
## Usage with TypeScript
You can pass types that were [generated with the Supabase CLI](/docs/reference/javascript/typescript-support#generating-types) to the Supabase Client to get enhanced type safety and auto completion:
### Browser client
Creating a new supabase client object:
```tsx
import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs'
import { Database } from '../database.types'
const supabaseClient = createBrowserSupabaseClient<Database>()
```
Retrieving a supabase client object from the SessionContext:
```tsx
import { useSupabaseClient } from '@supabase/auth-helpers-react'
import { Database } from '../database.types'
const supabaseClient = useSupabaseClient<Database>()
```
### Server client
```tsx
// Creating a new supabase server client object (e.g. in API route):
import type { NextApiRequest, NextApiResponse } from 'next'
import type { Database } from 'types_db'
export default async (req: NextApiRequest, res: NextApiResponse) => {
const supabaseServerClient = createServerSupabaseClient<Database>({
req,
res,
})
const {
data: { user },
} = await supabaseServerClient.auth.getUser()
res.status(200).json({ name: user?.name ?? '' })
}
```
## Client-side data fetching with RLS
For [row level security](https://supabase.com/docs/learn/auth-deep-dive/auth-row-level-security) to work properly when fetching data client-side, you need to make sure to use the `supabaseClient` from the `useSupabaseClient` hook and only run your query once the user is defined client-side in the `useUser()` hook:
```jsx
import { Auth, ThemeSupa } from '@supabase/auth-ui-react'
import { useUser, useSupabaseClient } from '@supabase/auth-helpers-react'
import { useEffect, useState } from 'react'
const LoginPage = () => {
const supabaseClient = useSupabaseClient()
const user = useUser()
const [data, setData] = useState()
// highlight-start
useEffect(() => {
async function loadData() {
const { data } = await supabaseClient.from('test').select('*')
setData(data)
}
// Only run query once user is logged in.
if (user) loadData()
}, [user])
// highlight-end
if (!user)
return (
<Auth
redirectTo="http://localhost:3000/"
appearance={{ theme: ThemeSupa }}
supabaseClient={supabaseClient}
providers={['google', 'github']}
socialLayout="horizontal"
/>
)
return (
<>
<button onClick={() => supabaseClient.auth.signOut()}>Sign out</button>
<p>user:</p>
<pre>{JSON.stringify(user, null, 2)}</pre>
<p>client-side data fetching with RLS</p>
<pre>{JSON.stringify(data, null, 2)}</pre>
</>
)
}
export default LoginPage
```
## Server-side rendering (SSR)
Create a server supabase client to retrieve the logged in user's session:
```jsx title="pages/profile.js"
import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs'
export default function Profile({ user }) {
return <div>Hello {user.name}</div>
}
export const getServerSideProps = async (ctx) => {
// Create authenticated Supabase Client
const supabase = createServerSupabaseClient(ctx)
// Check if we have a session
const {
data: { session },
} = await supabase.auth.getSession()
if (!session)
return {
redirect: {
destination: '/',
permanent: false,
},
}
return {
props: {
initialSession: session,
user: session.user,
},
}
}
```
## Server-side data fetching with RLS
You can use the server supabase client to run [row level security](https://supabase.com/docs/learn/auth-deep-dive/auth-row-level-security) authenticated queries server-side:
<Tabs
groupId="language"
defaultValue="js"
values={[
{label: 'JavaScript', value: 'js'},
{label: 'TypeScript', value: 'ts'},
]}>
<TabItem value="js">
```jsx
import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs'
export default function ProtectedPage({ user, data }) {
return (
<>
<div>Protected content for {user.email}</div>
<pre>{JSON.stringify(data, null, 2)}</pre>
<pre>{JSON.stringify(user, null, 2)}</pre>
</>
)
}
export const getServerSideProps = async (ctx) => {
// Create authenticated Supabase Client
const supabase = createServerSupabaseClient(ctx)
// Check if we have a session
const {
data: { session },
} = await supabase.auth.getSession()
if (!session)
return {
redirect: {
destination: '/',
permanent: false,
},
}
// Run queries with RLS on the server
const { data } = await supabase.from('users').select('*')
return {
props: {
initialSession: session,
user: session.user,
data: data ?? [],
},
}
}
```
</TabItem>
<TabItem value="ts">
```tsx
import { User, createServerSupabaseClient } from '@supabase/auth-helpers-nextjs'
import { GetServerSidePropsContext } from 'next'
export default function ProtectedPage({
user,
data,
}: {
user: User
data: any
}) {
return (
<>
<div>Protected content for {user.email}</div>
<pre>{JSON.stringify(data, null, 2)}</pre>
<pre>{JSON.stringify(user, null, 2)}</pre>
</>
)
}
export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
// Create authenticated Supabase Client
const supabase = createServerSupabaseClient(ctx)
// Check if we have a session
const {
data: { session },
} = await supabase.auth.getSession()
if (!session)
return {
redirect: {
destination: '/',
permanent: false,
},
}
// Run queries with RLS on the server
const { data } = await supabase.from('users').select('*')
return {
props: {
initialSession: session,
user: session.user,
data: data ?? [],
},
}
}
```
</TabItem>
</Tabs>
## Server-side data fetching to OAuth APIs using `provider_token`
When using third-party auth providers, sessions are initiated with an additional `provider_token` field which is persisted in the auth cookie and can be accessed within the session object. The `provider_token` can be used to make API requests to the OAuth provider's API endpoints on behalf of the logged-in user.
<Tabs
groupId="language"
defaultValue="js"
values={[
{label: 'JavaScript', value: 'js'},
{label: 'TypeScript', value: 'ts'},
]}>
<TabItem value="js">
```jsx
import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs'
export default function ProtectedPage({ user, allRepos }) {
return (
<>
<div>Protected content for {user.email}</div>
<p>Data fetched with provider token:</p>
<pre>{JSON.stringify(allRepos, null, 2)}</pre>
<p>user:</p>
<pre>{JSON.stringify(user, null, 2)}</pre>
</>
)
}
export const getServerSideProps = async (ctx) => {
// Create authenticated Supabase Client
const supabase = createServerSupabaseClient(ctx)
// Check if we have a session
const {
data: { session },
} = await supabase.auth.getSession()
if (!session)
return {
redirect: {
destination: '/',
permanent: false,
},
}
// Retrieve provider_token & logged in user's third-party id from metadata
const { provider_token, user } = session
const userId = user.user_metadata.user_name
const allRepos = await (
await fetch(`https://api.github.com/search/repositories?q=user:${userId}`, {
method: 'GET',
headers: {
Authorization: `token ${provider_token}`,
},
})
).json()
return { props: { user, allRepos } }
}
```
</TabItem>
<TabItem value="ts">
```tsx
import { User, createServerSupabaseClient } from '@supabase/auth-helpers-nextjs'
import { GetServerSidePropsContext } from 'next'
export default function ProtectedPage({
user,
allRepos,
}: {
user: User
allRepos: any
}) {
return (
<>
<div>Protected content for {user.email}</div>
<p>Data fetched with provider token:</p>
<pre>{JSON.stringify(allRepos, null, 2)}</pre>
<p>user:</p>
<pre>{JSON.stringify(user, null, 2)}</pre>
</>
)
}
export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
// Create authenticated Supabase Client
const supabase = createServerSupabaseClient(ctx)
// Check if we have a session
const {
data: { session },
} = await supabase.auth.getSession()
if (!session)
return {
redirect: {
destination: '/',
permanent: false,
},
}
// Retrieve provider_token & logged in user's third-party id from metadata
const { provider_token, user } = session
const userId = user.user_metadata.user_name
const allRepos = await (
await fetch(`https://api.github.com/search/repositories?q=user:${userId}`, {
method: 'GET',
headers: {
Authorization: `token ${provider_token}`,
},
})
).json()
return { props: { user, allRepos } }
}
```
</TabItem>
</Tabs>
## Protecting API routes
Create a server supabase client to retrieve the logged in user's session:
<Tabs
groupId="language"
defaultValue="js"
values={[
{label: 'JavaScript', value: 'js'},
{label: 'TypeScript', value: 'ts'},
]}>
<TabItem value="js">
```jsx title="pages/api/protected-route.js"
import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs'
const ProtectedRoute = async (req, res) => {
// Create authenticated Supabase Client
const supabase = createServerSupabaseClient({ req, res })
// Check if we have a session
const {
data: { session },
} = await supabase.auth.getSession()
if (!session)
return res.status(401).json({
error: 'not_authenticated',
description:
'The user does not have an active session or is not authenticated',
})
// Run queries with RLS on the server
const { data } = await supabase.from('test').select('*')
res.json(data)
}
export default ProtectedRoute
```
</TabItem>
<TabItem value="ts">
```tsx title="pages/api/protected-route.ts"
import { NextApiHandler } from 'next'
import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs'
const ProtectedRoute: NextApiHandler = async (req, res) => {
// Create authenticated Supabase Client
const supabase = createServerSupabaseClient({ req, res })
// Check if we have a session
const {
data: { session },
} = await supabase.auth.getSession()
if (!session)
return res.status(401).json({
error: 'not_authenticated',
description:
'The user does not have an active session or is not authenticated',
})
// Run queries with RLS on the server
const { data } = await supabase.from('test').select('*')
res.json(data)
}
export default ProtectedRoute
```
</TabItem>
</Tabs>
## Protecting routes with [Nextjs Middleware](https://nextjs.org/docs/middleware)
As an alternative to protecting individual pages you can use a `middleware` file to protect the entire directory or those that match the config object. In the following example, all requests to `/middleware-protected/*` will check whether a user is signed in, if successful the request will be forwarded to the destination route, otherwise the user will be redirected:
```ts title="middleware.ts"
import { createMiddlewareSupabaseClient } from '@supabase/auth-helpers-nextjs'
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export async function middleware(req: NextRequest) {
// We need to create a response and hand it to the supabase client to be able to modify the response headers.
const res = NextResponse.next()
// Create authenticated Supabase Client.
const supabase = createMiddlewareSupabaseClient({ req, res })
// Check if we have a session
const {
data: { session },
} = await supabase.auth.getSession()
// Check auth condition
if (session?.user.email?.endsWith('@gmail.com')) {
// Authentication successful, forward request to protected route.
return res
}
// Auth condition not met, redirect to home page.
const redirectUrl = req.nextUrl.clone()
redirectUrl.pathname = '/'
redirectUrl.searchParams.set(`redirectedFrom`, req.nextUrl.pathname)
return NextResponse.redirect(redirectUrl)
}
export const config = {
matcher: '/middleware-protected',
}
```
## Migration Guide {#migration}
### Migrating to `0.5.X`
To make these helpers more flexible as well as more maintainable and easier to upgrade for new versions of Next.js, we're stripping them down to the most useful part which is managing the cookies and giving you an authenticated supabase-js client in any environment (client, server, middleware/edge).
Therefore we're marking the `withApiAuth`, `withPageAuth`, and `withMiddlewareAuth` higher order functions as deprectaed and they will be removed in the next **minor** release (v0.6.X).
Please follow the steps below to update your API routes, pages, and middleware handlers. Thanks!
#### `withApiAuth` deprecated!
Use `createServerSupabaseClient` within your `NextApiHandler`:
<Tabs
defaultValue="before"
values={[
{label: 'Before', value: 'before'},
{label: 'After', value: 'after'},
]}>
<TabItem value="before">
```tsx title="pages/api/protected-route.ts"
import { withApiAuth } from '@supabase/auth-helpers-nextjs'
export default withApiAuth(async function ProtectedRoute(req, res, supabase) {
// Run queries with RLS on the server
const { data } = await supabase.from('test').select('*')
res.json(data)
})
```
</TabItem>
<TabItem value="after">
```tsx title="pages/api/protected-route.ts"
import { NextApiHandler } from 'next'
import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs'
const ProtectedRoute: NextApiHandler = async (req, res) => {
// Create authenticated Supabase Client
const supabase = createServerSupabaseClient({ req, res })
// Check if we have a session
const {
data: { session },
} = await supabase.auth.getSession()
if (!session)
return res.status(401).json({
error: 'not_authenticated',
description:
'The user does not have an active session or is not authenticated',
})
// Run queries with RLS on the server
const { data } = await supabase.from('test').select('*')
res.json(data)
}
export default ProtectedRoute
```
</TabItem>
</Tabs>
#### `withPageAuth` deprecated!
Use `createServerSupabaseClient` within `getServerSideProps`:
<Tabs
defaultValue="before"
values={[
{label: 'Before', value: 'before'},
{label: 'After', value: 'after'},
]}>
<TabItem value="before">
```tsx title="pages/profile.tsx"
import { withPageAuth, User } from '@supabase/auth-helpers-nextjs'
export default function Profile({ user }: { user: User }) {
return <pre>{JSON.stringify(user, null, 2)}</pre>
}
export const getServerSideProps = withPageAuth({ redirectTo: '/' })
```
</TabItem>
<TabItem value="after">
```tsx title="pages/profile.js"
import { createServerSupabaseClient, User } from '@supabase/auth-helpers-nextjs'
import { GetServerSidePropsContext } from 'next'
export default function Profile({ user }: { user: User }) {
return <pre>{JSON.stringify(user, null, 2)}</pre>
}
export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
// Create authenticated Supabase Client
const supabase = createServerSupabaseClient(ctx)
// Check if we have a session
const {
data: { session },
} = await supabase.auth.getSession()
if (!session)
return {
redirect: {
destination: '/',
permanent: false,
},
}
return {
props: {
initialSession: session,
user: session.user,
},
}
}
```
</TabItem>
</Tabs>
#### `withMiddlewareAuth` deprecated!
<Tabs
defaultValue="before"
values={[
{label: 'Before', value: 'before'},
{label: 'After', value: 'after'},
]}>
<TabItem value="before">
```tsx title="middleware.ts"
import { withMiddlewareAuth } from '@supabase/auth-helpers-nextjs'
export const middleware = withMiddlewareAuth({
redirectTo: '/',
authGuard: {
isPermitted: async (user) => {
return user.email?.endsWith('@gmail.com') ?? false
},
redirectTo: '/insufficient-permissions',
},
})
export const config = {
matcher: '/middleware-protected',
}
```
</TabItem>
<TabItem value="after">
```tsx title="middleware.ts"
import { createMiddlewareSupabaseClient } from '@supabase/auth-helpers-nextjs'
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export async function middleware(req: NextRequest) {
// We need to create a response and hand it to the supabase client to be able to modify the response headers.
const res = NextResponse.next()
// Create authenticated Supabase Client.
const supabase = createMiddlewareSupabaseClient({ req, res })
// Check if we have a session
const {
data: { session },
} = await supabase.auth.getSession()
// Check auth condition
if (session?.user.email?.endsWith('@gmail.com')) {
// Authentication successful, forward request to protected route.
return res
}
// Auth condition not met, redirect to home page.
const redirectUrl = req.nextUrl.clone()
redirectUrl.pathname = '/'
redirectUrl.searchParams.set(`redirectedFrom`, req.nextUrl.pathname)
return NextResponse.redirect(redirectUrl)
}
export const config = {
matcher: '/middleware-protected',
}
```
</TabItem>
</Tabs>
### Migrating to `0.4.X` and supabase-js v2
- With the update to `supabase-js` v2 the `auth` API routes are no longer required, therefore you can go ahead and delete your `auth` directory under the `/pages/api/` directory. Please refer to the [v2 migration guide](https://supabase.com/docs/reference/javascript/upgrade-guide) for the full set of changes within supabase-js.
- The `/api/auth/logout` API route has been removed, please use the `signout` method instead:
```jsx
<button
onClick={async () => {
await supabaseClient.auth.signOut()
router.push('/')
}}
>
Logout
</button>
```
- The `supabaseClient` and `supabaseServerClient` have been removed in favor of the `createBrowserSupabaseClient` and `createServerSupabaseClient` methods. This allows you to provide the CLI-generated types to the client:
```tsx
// client-side
import type { Database } from 'types_db'
const [supabaseClient] = useState(() =>
createBrowserSupabaseClient<Database>()
)
// server-side API route
import type { NextApiRequest, NextApiResponse } from 'next'
import type { Database } from 'types_db'
export default async (req: NextApiRequest, res: NextApiResponse) => {
const supabaseServerClient = createServerSupabaseClient<Database>({
req,
res,
})
const {
data: { user },
} = await supabaseServerClient.auth.getUser()
res.status(200).json({ name: user?.name ?? '' })
}
```
- The `UserProvider` has been replaced by the `SessionContextProvider`. Make sure to wrap your `pages/_app.js` componenent with the `SessionContextProvider`. Then, throughout your application you can use the `useSessionContext` hook to get the `session` and the `useSupabaseClient` hook to get an authenticated `supabaseClient`.
- The `useUser` hook now returns the `user` object or `null`.
- Usage with TypeScript: You can pass types that were [generated with the Supabase CLI](/docs/reference/javascript/typescript-support#generating-types) to the Supabase Client to get enhanced type safety and auto completion:
Creating a new supabase client object:
```tsx
import { Database } from '../database.types'
const [supabaseClient] = useState(() => createBrowserSupabaseClient<Database>())
```
Retrieving a supabase client object from the SessionContext:
```tsx
import { useSupabaseClient } from '@supabase/auth-helpers-react'
import { Database } from '../database.types'
const supabaseClient = useSupabaseClient<Database>()
```
@@ -1,906 +0,0 @@
---
id: remix
title: Supabase Auth with Remix
description: Authentication helpers for loaders and actions in Remix.
sidebar_label: 'Remix'
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
This submodule provides convenience helpers for implementing user authentication in Remix applications.
## Install the Remix helper library
<Tabs
groupId="install"
defaultValue="npm"
values={[
{label: 'npm', value: 'npm'},
{label: 'Yarn', value: 'yarn'},
]}>
<TabItem value="npm">
```sh
npm install @supabase/auth-helpers-remix
```
This library supports the following tooling versions:
- Remix: `>=1.7.2`
</TabItem>
<TabItem value="yarn">
```sh
yarn add @supabase/auth-helpers-remix
```
This library supports the following tooling versions:
- Remix: `>=1.7.2`
</TabItem>
</Tabs>
## Set up environment variables
Retrieve your project URL and anon key in your project's [API settings](https://app.supabase.com/project/_/settings/api) in the Dashboard to set up the following environment variables. For local development you can set them in a `.env` file. See an [example](https://github.com/supabase/auth-helpers/blob/main/examples/remix/.env.example).
```bash title=".env"
SUPABASE_URL=YOUR_SUPABASE_URL
SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
```
## Basic Setup
In your "root route" load environment variables and session and make them available client-side:
<Tabs
groupId="language"
defaultValue="js"
values={[
{label: 'JavaScript', value: 'js'},
{label: 'TypeScript', value: 'ts'},
]}>
<TabItem value="js">
```jsx title="app/root.jsx"
export const loader = async ({ request }) => {
// Environment variables may be stored somewhere other than `process.env` in runtimes other than node.
// We need to pipe these Supabase environment variables to the browser.
const { SUPABASE_URL, SUPABASE_ANON_KEY } = process.env
// We can retrieve the session on the server and hand it to the client.
// This is used to make sure the session is available immediately upon rendering.
const response = new Response()
const supabase = createServerClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_ANON_KEY!,
{ request, response }
)
const {
data: { session: initialSession },
} = await supabase.auth.getSession()
// In order for the set-cookie header to be set, headers must be returned as part of the loader response.
return json(
{
initialSession,
env: {
SUPABASE_URL,
SUPABASE_ANON_KEY,
},
},
{
headers: response.headers,
}
)
}
```
</TabItem>
<TabItem value="ts">
```tsx title="app/root.tsx"
export const loader: LoaderFunction = async ({ request }) => {
// Environment variables may be stored somewhere other than `process.env` in runtimes other than node.
// We need to pipe these Supabase environment variables to the browser.
const { SUPABASE_URL, SUPABASE_ANON_KEY } = process.env
// We can retrieve the session on the server and hand it to the client.
// This is used to make sure the session is available immediately upon rendering.
const response = new Response()
const supabase = createServerClient<Database>(
process.env.SUPABASE_URL!,
process.env.SUPABASE_ANON_KEY!,
{ request, response }
)
const {
data: { session: initialSession },
} = await supabase.auth.getSession()
// In order for the set-cookie header to be set, headers must be returned as part of the loader response.
return json(
{
initialSession,
env: {
SUPABASE_URL,
SUPABASE_ANON_KEY,
},
},
{
headers: response.headers,
}
)
}
```
</TabItem>
</Tabs>
Next, upon the initial client-side rendering of your application, set up a browser client and listen to session changes and expose both throughout your routes via the outlet context:
<Tabs
groupId="language"
defaultValue="js"
values={[
{label: 'JavaScript', value: 'js'},
{label: 'TypeScript', value: 'ts'},
]}>
<TabItem value="js">
```jsx title="app/root.jsx"
import { useEffect, useState } from 'react'
import { json } from '@remix-run/node'
import { Outlet, useLoaderData } from '@remix-run/react'
import {
createServerClient,
createBrowserClient,
} from '@supabase/auth-helpers-remix'
export const loader: LoaderFunction = async ({ request }) => {
// ... see loader function above.
}
export default function App() {
const { env, initialSession } = useLoaderData()
const [supabase, setSupabase] = useState(null)
const [session, setSession] = useState(initialSession)
const context = { supabase, session }
useEffect(() => {
if (!supabase) {
const supabase = createBrowserClient(
env.SUPABASE_URL,
env.SUPABASE_ANON_KEY
)
setSupabase(supabase)
const {
data: { subscription },
} = supabase.auth.onAuthStateChange((_, session) => setSession(session))
return () => {
subscription.unsubscribe()
}
}
}, [])
return (
<html lang="en">
<body>
<Outlet context={context} />
</body>
</html>
)
}
```
</TabItem>
<TabItem value="ts">
```tsx title="app/root.tsx"
import { useEffect, useState } from 'react'
import { json, LoaderFunction } from '@remix-run/node'
import { Outlet, useLoaderData } from '@remix-run/react'
import {
createServerClient,
createBrowserClient,
supabase,
Session,
} from '@supabase/auth-helpers-remix'
import { Database } from '../db_types'
export type ContextType = {
supabase: supabase<Database> | null
session: Session | null
}
type LoaderData = {
env: { SUPABASE_URL: string; SUPABASE_ANON_KEY: string }
initialSession: Session | null
}
export const loader: LoaderFunction = async ({ request }) => {
// ... see loader function above.
}
export default function App() {
const { env, initialSession } = useLoaderData<LoaderData>()
const [supabase, setSupabase] = useState<supabase | null>(null)
const [session, setSession] = useState<Session | null>(initialSession)
const context: ContextType = { supabase, session }
useEffect(() => {
if (!supabase) {
const supabase = createBrowserClient<Database>(
env.SUPABASE_URL,
env.SUPABASE_ANON_KEY
)
setSupabase(supabase)
const {
data: { subscription },
} = supabase.auth.onAuthStateChange((_, session) => setSession(session))
return () => {
subscription.unsubscribe()
}
}
}, [])
return (
<html lang="en">
<body>
<Outlet context={context} />
</body>
</html>
)
}
```
</TabItem>
</Tabs>
Now the supabase client and session are available throughout the application via the `useOutletContext`:
<Tabs
groupId="language"
defaultValue="js"
values={[
{label: 'JavaScript', value: 'js'},
{label: 'TypeScript', value: 'ts'},
]}>
<TabItem value="js">
```jsx title="app/routes/index.jsx"
import { useOutletContext } from '@remix-run/react'
export default function Index() {
const { supabase, session } = useOutletContext()
return <pre>{JSON.stringify({ session }, null, 2)}</pre>
}
```
</TabItem>
<TabItem value="ts">
```tsx title="app/routes/index.tsx"
import { useOutletContext } from '@remix-run/react'
import type { ContextType } from '../root'
export default function Index() {
const { supabase, session } = useOutletContext<ContextType>()
return <pre>{JSON.stringify({ session }, null, 2)}</pre>
}
```
</TabItem>
</Tabs>
You can find a full working example in the [source code on GitHub](https://github.com/supabase/auth-helpers/tree/main/examples/remix).
## Usage with TypeScript
You can pass types that were [generated with the Supabase CLI](/docs/reference/javascript/typescript-support#generating-types) to the `createServerClient` or `createBrowserClient` functions to get enhanced type safety and auto completion:
### Server-side
```tsx
import { createServerClient } from '@supabase/auth-helpers-remix'
import { Database } from '../../db_types'
export const loader = async ({ request }) => {
const response = new Response()
const supabase = createServerClient<Database>(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY,
{ request, response }
)
}
```
### Client-side
```tsx
import { createBrowserClient } from '@supabase/auth-helpers-remix'
import { Database } from '../../db_types'
const supabase = createBrowserClient<Database>(SUPABASE_URL, SUPABASE_ANON_KEY)
```
## Loader
Loader functions run on the server immediately before the component is rendered. They respond to all GET requests on a route. You can create an authenticated Supabase client by calling the `createServerClient` function and passing it your `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and a `Request` and `Response`.
<Tabs
groupId="language"
defaultValue="js"
values={[
{label: 'JavaScript', value: 'js'},
{label: 'TypeScript', value: 'ts'},
]}>
<TabItem value="js">
```jsx
import { json } from '@remix-run/node' // change this import to whatever runtime you are using
import { createServerClient } from '@supabase/auth-helpers-remix'
export const loader = async ({ request }) => {
const response = new Response()
// an empty response is required for the auth helpers
// to set cookies to manage auth
const supabase = createServerClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY,
{ request, response }
)
const { data } = await supabase.from('test').select('*')
// in order for the set-cookie header to be set,
// headers must be returned as part of the loader response
return json(
{ data },
{
headers: response.headers,
}
)
}
```
</TabItem>
<TabItem value="ts">
```tsx
import { LoaderFunction, json } from '@remix-run/node' // change this import to whatever runtime you are using
import { createServerClient } from '@supabase/auth-helpers-remix'
export const loader: LoaderFunction = async ({ request }) => {
const response = new Response()
const supabase = createServerClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY,
{ request, response }
)
const { data } = await supabase.from('test').select('*')
return json(
{ data },
{
headers: response.headers,
}
)
}
```
</TabItem>
</Tabs>
> Supabase will set cookie headers to manage the user's auth session, therefore, the `response.headers` must be returned from the `Loader` function.
## Action
Action functions run on the server and respond to HTTP requests to a route, other than GET - POST, PUT, PATCH, DELETE etc. You can create an authenticated Supabase client by calling the `createServerClient` function and passing it your `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and a `Request` and `Response`.
<Tabs
groupId="language"
defaultValue="js"
values={[
{label: 'JavaScript', value: 'js'},
{label: 'TypeScript', value: 'ts'},
]}>
<TabItem value="js">
```jsx
import { json } from '@remix-run/node' // change this import to whatever runtime you are using
import { createServerClient } from '@supabase/auth-helpers-remix'
export const action = async ({ request }) => {
const response = new Response()
const supabase = createServerClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY,
{ request, response }
)
const { data } = await supabase.from('test').select('*')
return json(
{ data },
{
headers: response.headers,
}
)
}
```
</TabItem>
<TabItem value="ts">
```tsx
import { ActionFunction, json } from '@remix-run/node' // change this import to whatever runtime you are using
import { createServerClient } from '@supabase/auth-helpers-remix'
export const action: ActionFunction = async ({ request }) => {
const response = new Response()
const supabase = createServerClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY,
{ request, response }
)
const { data } = await supabase.from('test').select('*')
return json(
{ data },
{
headers: response.headers,
}
)
}
```
</TabItem>
</Tabs>
> Supabase will set cookie headers to manage the user's auth session, therefore, the `response.headers` must be returned from the `Action` function.
## Session and User
You can determine if a user is authenticated by checking their session using the `getSession` function.
```jsx
const {
data: { session },
} = await supabase.auth.getSession()
```
The session contains a user property.
```jsx
const user = session?.user
```
## Authentication UI
### Pre-built Auth UI
We recommend using our [pre-built Auth UI](/docs/guides/auth/auth-helpers/auth-ui) for authenticating users. It supports custom themes and extensible styles to match your brand and aesthetic.
### Custom Auth UI
Should you prefer to build your own Auth UI, you can use our [JavaScript Library](/docs/reference/javascript/) to interact with Supabase Auth from the client-side.
<Tabs
groupId="language"
defaultValue="js"
values={[
{label: 'JavaScript', value: 'js'},
{label: 'TypeScript', value: 'ts'},
]}>
<TabItem value="js">
```jsx title="app/routes/signin.jsx"
import { useOutletContext } from '@remix-run/react'
export default function Auth() {
const { supabase, session } = useOutletContext()
const handleSubmit = async (event) => {
event.preventDefault()
if (!supabase) return
const formData = new FormData(event.currentTarget)
const email = formData.get('loginEmail')
const password = formData.get('loginPassword')
// Sign in
const { error } = await supabase.auth.signInWithPassword({
email,
password,
})
if (error) alert(error.message)
}
if (session)
return (
<div>
<pre>{JSON.stringify({ session }, null, 2)}</pre>
</div>
)
// Auth form
return (
<div>
<form onSubmit={handleSubmit}>
<h1>Custom login form:</h1>
<div>
<label htmlFor="loginEmail">Email:</label>
<input type="text" id="loginEmail" name="loginEmail" required />
</div>
<div>
<label htmlFor="loginPassword">Password:</label>
<input
type="password"
id="loginPassword"
name="loginPassword"
required
/>
</div>
<button type="submit">Login</button>
</form>
</div>
)
}
```
</TabItem>
<TabItem value="ts">
```tsx title="app/routes/signin.tsx"
import { useOutletContext } from '@remix-run/react'
import type { ContextType } from '../root'
export default function Auth() {
const { supabase, session } = useOutletContext<ContextType>()
const handleSubmit: React.FormEventHandler<HTMLFormElement> = async (
event
) => {
event.preventDefault()
if (!supabase) return
const formData = new FormData(event.currentTarget)
const email = formData.get('loginEmail') as string
const password = formData.get('loginPassword') as string
// Sign in
const { error } = await supabase.auth.signInWithPassword({
email,
password,
})
if (error) alert(error.message)
}
if (session)
return (
<div>
<pre>{JSON.stringify({ session }, null, 2)}</pre>
</div>
)
// Auth form
return (
<div>
<form onSubmit={handleSubmit}>
<h1>Custom login form:</h1>
<div>
<label htmlFor="loginEmail">Email:</label>
<input type="text" id="loginEmail" name="loginEmail" required />
</div>
<div>
<label htmlFor="loginPassword">Password:</label>
<input
type="password"
id="loginPassword"
name="loginPassword"
required
/>
</div>
<button type="submit">Login</button>
</form>
</div>
)
}
```
</TabItem>
</Tabs>
## Subscribe to realtime events
[Supabase Realtime](/docs/guides/realtime) uses WebSockets to send database changes to the connected clients.
We recommend loading the initial data server-side and then using the Supabase Realtime listener to update the client-side state as changes occur:
<Tabs
groupId="language"
defaultValue="js"
values={[
{label: 'JavaScript', value: 'js'},
{label: 'TypeScript', value: 'ts'},
]}>
<TabItem value="js">
```jsx title="app/routes/realtime.jsx"
import { useEffect, useState } from 'react'
import { json } from '@remix-run/node'
import { useLoaderData } from '@remix-run/react'
import { useOutletContext } from '@remix-run/react'
import { createServerClient } from '@supabase/auth-helpers-remix'
// Fetch the initial data server-side, then subscribe to updates client-side.
export const loader = async ({ request }) => {
const response = new Response()
const supabaseClient = createServerClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY,
{ request, response }
)
const { data, error } = await supabaseClient.from('test').select('*')
if (error) {
throw error
}
// in order for the set-cookie header to be set,
// headers must be returned as part of the loader response
return json(
{ data },
{
headers: response.headers,
}
)
}
export default function SubscribeToRealtime() {
const { session, supabase } = useOutletContext()
const { data: serverLoadedData } = useLoaderData()
const [data, setData] = useState(serverLoadedData)
useEffect(() => {
if (supabase && session) {
// Subscribe to updates client-side
const channel = supabase
.channel('test')
.on(
'postgres_changes',
{ event: 'INSERT', schema: 'public', table: 'test' },
(payload) => {
setData((data) => [...data, payload.new])
}
)
.subscribe()
return () => {
supabase.removeChannel(channel)
}
}
}, [session, supabase])
return <pre>{JSON.stringify(data, null, 2)}</pre>
}
```
</TabItem>
<TabItem value="ts">
```tsx title="app/routes/realtime.tsx"
import { useEffect, useState } from 'react'
import { json, LoaderFunction } from '@remix-run/node'
import { useLoaderData } from '@remix-run/react'
import { useOutletContext } from '@remix-run/react'
import { createServerClient } from '@supabase/auth-helpers-remix'
import type { ContextType } from '../root'
import { Database } from '../../db_types'
type TestData = Database['public']['Tables']['test']['Row']
// Fetch the initial data server-side, then subscribe to updates client-side.
export const loader: LoaderFunction = async ({ request }) => {
const response = new Response()
const supabaseClient = createServerClient<Database>(
process.env.SUPABASE_URL!,
process.env.SUPABASE_ANON_KEY!,
{ request, response }
)
const { data, error } = await supabaseClient.from('test').select('*')
if (error) {
throw error
}
// in order for the set-cookie header to be set,
// headers must be returned as part of the loader response
return json(
{ data },
{
headers: response.headers,
}
)
}
export default function SubscribeToRealtime() {
const { session, supabase } = useOutletContext<ContextType>()
const { data: serverLoadedData } = useLoaderData<{ data: TestData[] }>()
const [data, setData] = useState<TestData[]>(serverLoadedData)
useEffect(() => {
if (supabase && session) {
// Subscribe to updates client-side
const channel = supabase
.channel('test')
.on(
'postgres_changes',
{ event: 'INSERT', schema: 'public', table: 'test' },
(payload) => {
setData((data) => [...data, payload.new as TestData])
}
)
.subscribe()
return () => {
supabase.removeChannel(channel)
}
}
}, [session, supabase])
return <pre>{JSON.stringify(data, null, 2)}</pre>
}
```
</TabItem>
</Tabs>
## Server-side data fetching to OAuth APIs using `provider_token`
When using third-party auth providers, sessions are initiated with an additional `provider_token` field which is persisted in the auth cookie and can be accessed within the session object. The `provider_token` can be used to make API requests to the OAuth provider's API endpoints on behalf of the logged-in user.
<Tabs
groupId="language"
defaultValue="js"
values={[
{label: 'JavaScript', value: 'js'},
{label: 'TypeScript', value: 'ts'},
]}>
<TabItem value="js">
```jsx
import { json, redirect } from '@remix-run/node' // change this import to whatever runtime you are using
import { useLoaderData } from '@remix-run/react'
import { createServerClient } from '@supabase/auth-helpers-remix'
export const loader = async ({ request }) => {
const response = new Response()
const supabase = createServerClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY,
{ request, response }
)
const {
data: { session },
} = await supabase.auth.getSession()
if (!session) {
// there is no session, therefore, we are redirecting
// to the landing page. we still need to return
// response.headers to attach the set-cookie header
return redirect('/', {
headers: response.headers,
})
}
// Retrieve provider_token & logged in user's third-party id from metadata
const { provider_token, user } = session
const userId = user.user_metadata.user_name
const allRepos = await (
await fetch(`https://api.github.com/search/repositories?q=user:${userId}`, {
method: 'GET',
headers: {
Authorization: `token ${provider_token}`,
},
})
).json()
// in order for the set-cookie header to be set,
// headers must be returned as part of the loader response
return json(
{ user, allRepos },
{
headers: response.headers,
}
)
}
export default function ProtectedPage() {
// by fetching the user in the loader, we ensure it is available
// for first SSR render - no flashing of incorrect state
const { user, allRepos } = useLoaderData()
return <pre>{JSON.stringify({ user, allRepos }, null, 2)}</pre>
}
```
</TabItem>
<TabItem value="ts">
```tsx
import { json, LoaderFunction, redirect } from '@remix-run/node' // change this import to whatever runtime you are using
import { useLoaderData } from '@remix-run/react'
import { createServerClient, User } from '@supabase/auth-helpers-remix'
import { Database } from '../../db_types'
export const loader: LoaderFunction = async ({ request }) => {
const response = new Response()
const supabase = createServerClient<Database>(
process.env.SUPABASE_URL!,
process.env.SUPABASE_ANON_KEY!,
{ request, response }
)
const {
data: { session },
} = await supabase.auth.getSession()
if (!session) {
// there is no session, therefore, we are redirecting
// to the landing page. we still need to return
// response.headers to attach the set-cookie header
return redirect('/', {
headers: response.headers,
})
}
// Retrieve provider_token & logged in user's third-party id from metadata
const { provider_token, user } = session
const userId = user.user_metadata.user_name
const allRepos = await (
await fetch(`https://api.github.com/search/repositories?q=user:${userId}`, {
method: 'GET',
headers: {
Authorization: `token ${provider_token}`,
},
})
).json()
// in order for the set-cookie header to be set,
// headers must be returned as part of the loader response
return json(
{ user, allRepos },
{
headers: response.headers,
}
)
}
export default function ProtectedPage() {
// by fetching the user in the loader, we ensure it is available
// for first SSR render - no flashing of incorrect state
const { user, allRepos } = useLoaderData<{ user: User; allRepos: any }>()
return <pre>{JSON.stringify({ user, allRepos }, null, 2)}</pre>
}
```
</TabItem>
</Tabs>
@@ -1,897 +0,0 @@
---
id: sveltekit
title: Supabase Auth with SvelteKit
description: Convenience helpers for implementing user authentication in SvelteKit.
sidebar_label: SvelteKit
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
This submodule provides convenience helpers for implementing user authentication in [SvelteKit](https://kit.svelte.dev/) applications.
## Installation
This library supports Node.js `^16.15.0`.
<Tabs
groupId="install"
defaultValue="npm"
values={[
{label: 'npm', value: 'npm'},
{label: 'Yarn', value: 'yarn'},
]}>
<TabItem value="npm">
```sh
npm install @supabase/auth-helpers-sveltekit
```
</TabItem>
<TabItem value="yarn">
```sh
yarn add @supabase/auth-helpers-sveltekit
```
</TabItem>
</Tabs>
## Getting Started
### Configuration
Set up the fillowing env vars. For local development you can set them in a `.env` file. See an [example](https://github.com/supabase/auth-helpers/blob/main/examples/sveltekit/.env.example).
```bash
# Find these in your Supabase project settings > API
PUBLIC_SUPABASE_URL=https://your-project.supabase.co
PUBLIC_SUPABASE_ANON_KEY=your-anon-key
```
### Set up the Supabase client
Start off by creating a `db.ts` file inside of the `src/lib` directory and instantiate the `supabaseClient`.
```ts title="src/lib/db.ts"
import { createClient } from '@supabase/supabase-js'
import { setupSupabaseHelpers } from '@supabase/auth-helpers-sveltekit'
import { dev } from '$app/environment'
import { env } from '$env/dynamic/public'
// or use the static env
// import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public';
export const supabaseClient = createClient(
env.PUBLIC_SUPABASE_URL,
env.PUBLIC_SUPABASE_ANON_KEY,
{
persistSession: false,
autoRefreshToken: false,
}
)
setupSupabaseHelpers({
supabaseClient,
cookieOptions: {
secure: !dev,
},
})
```
### Initialize the client
Edit your `+layout.svelte` file and set up the client-side.
```html title="src/routes/+layout.svelte"
<script lang="ts">
// make sure the supabase instance is initialized on the client
import '$lib/db'
import { startSupabaseSessionSync } from '@supabase/auth-helpers-sveltekit'
import { page } from '$app/stores'
import { invalidateAll } from '$app/navigation'
// this sets up automatic token refreshing
startSupabaseSessionSync({
page,
handleRefresh: () => invalidateAll(),
})
</script>
<slot />
```
### Set up hooks
The `hooks.server.ts` file is where the heavy lifting of this library happens:
```ts title="src/hooks.server.ts"
// make sure the supabase instance is initialized on the server
import '$lib/db'
import { dev } from '$app/environment'
import { auth } from '@supabase/auth-helpers-sveltekit/server'
export const handle = auth()
// use the sequence helper if you have additional Handle methods
import { sequence } from '@sveltejs/kit/hooks'
export const handle = sequence(auth(), yourHandler)
```
There are three handle methods available:
- `callback()`:
This creates a handler for `/api/auth/callback`. The `client` forwards the session details here every time `onAuthStateChange` fires on the client-side. This is needed to set up the cookies for your application so that SSR works seamlessly.
- `session()`:
This parses the session from the cookie and populate it in locals
- `auth()`:
a shorthand for `sequence(callback(), session())` that uses both handlers
### Send session to client
In order to make the session available to the UI (e.g., pages and layouts), pass the session in the root layout load function:
```ts title="src/routes/+layout.server.ts"
import type { LayoutServerLoad } from './$types'
export const load: LayoutServerLoad = async ({ locals }) => {
return {
session: locals.session,
}
}
```
### Typings
In order to get the most out of TypeScript and IntelliSense, import the types into the `app.d.ts` type definition file that comes with your SvelteKit project.
```ts title="src/app.d.ts"
/// <reference types="@sveltejs/kit" />
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
// and what to do when importing types
declare namespace App {
interface Locals {
session: import('@supabase/auth-helpers-sveltekit').SupabaseSession
}
interface PageData {
session: import('@supabase/auth-helpers-sveltekit').SupabaseSession
}
// interface Error {}
// interface Platform {}
}
```
### Signing out
This library has provided a method to delete the session cookie.
Create a server only page with an action to delete the cookie
```ts title="src/routes/logout/+page.server.ts"
import { deleteSession } from '@supabase/auth-helpers-sveltekit/server'
import { redirect } from '@sveltejs/kit'
import type { Actions } from './$types'
export const actions: Actions = {
async default({ cookies }) {
deleteSession(cookies)
throw redirect(303, '/')
},
}
```
Then make a **POST** request with a form to the server only page above.
```html
<script lang="ts">
import { enhanceAndInvalidate } from '@supabase/auth-helpers-sveltekit'
</script>
<form action="/logout" method="post" use:enhanceAndInvalidate>
<button type="submit">Sign out</button>
</form>
```
### Basic setup
You can now determine if a user is authenticated on the client-side by checking that the `user` object in `$page.data.session` is defined.
```html title="src/routes/+page.svelte"
<script>
import { page } from '$app/stores'
</script>
{#if !$page.data.session.user}
<h1>I am not logged in</h1>
{:else}
<h1>Welcome {$page.data.session.user.email}</h1>
<p>I am logged in!</p>
{/if}
```
## Client-side data fetching with RLS
For [row level security](https://supabase.com/docs/learn/auth-deep-dive/auth-row-level-security) to work properly when fetching data client-side, you need to make sure to import the `{ supabaseClient }` from `$lib/db` and only run your query once the user is defined client-side in `$page.data.session`:
```html
<script>
import { supabaseClient } from '$lib/db'
import { page } from '$app/stores'
let loadedData = []
async function loadData() {
const { data } = await supabaseClient.from('test').select('*').limit(20)
loadedData = data
}
$: if ($page.data.session.user) {
loadData()
}
</script>
{#if $page.data.session.user}
<p>client-side data fetching with RLS</p>
<pre>{JSON.stringify(loadedData, null, 2)}</pre>
{/if}
```
## Server-side data fetching with RLS
```html title="src/routes/profile/+page.svelte"
<script>
/** @type {import('./$types').PageData} */
export let data
$: ({ user, tableData } = data)
</script>
<div>Protected content for {user.email}</div>
<pre>{JSON.stringify(tableData, null, 2)}</pre>
<pre>{JSON.stringify(user, null, 2)}</pre>
```
For [row level security](https://supabase.com/docs/learn/auth-deep-dive/auth-row-level-security) to work in a server environment, you need to use the `withAuth` helper to check if the user is authenticated. The helper extends the event with `session` and `getSupabaseClient()`:
```ts title="src/routes/profile/+page.ts"
import type { PageLoad } from './$types';
import { withAuth } from '@supabase/auth-helpers-sveltekit';
import { redirect } from '@sveltejs/kit';
interface TestTable {
id: string;
created_at: string;
}
export const load: PageLoad = withAuth(async ({ getSupabaseClient, session }) => {
if (!session.user) {
throw redirect(303, '/');
}
const { data: tableData } = await getSupabaseClient()
.from<TestTable>('test')
.select('*');
return {
user: session.user,
tableData
};
);
```
**Caution:**
Always use the instance returned by `getSupabaseClient()` directly!
```ts
// Bad
const supabaseClient = getSupabaseClient()
await supabaseClient.from('table1').select()
await supabaseClient.from('table2').select()
// Good
await getSupabaseClient().from('table1').select()
await getSupabaseClient().from('table2').select()
```
## Protecting API routes
Wrap an API Route to check that the user has a valid session. If they're not logged in the session is `null`.
```ts title="src/routes/api/protected-route/+server.ts"
import type { RequestHandler } from './$types';
import { withAuth } from '@supabase/auth-helpers-sveltekit';
import { json, redirect } from '@sveltejs/kit';
interface TestTable {
id: string;
created_at: string;
}
export const GET: RequestHandler = withAuth(async ({ session, getSupabaseClient }) => {
if (!session.user) {
throw redirect(303, '/');
}
const { data } = await getSupabaseClient()
.from<TestTable>('test')
.select('*');
return json({ data });
);
```
If you visit `/api/protected-route` without a valid session cookie, you will get a 303 response.
## Protecting Actions
Wrap an Action to check that the user has a valid session. If they're not logged in, the session is `null`.
```ts title="src/routes/posts/+page.server.ts"
import type { Actions } from './$types'
import { withAuth } from '@supabase/auth-helpers-sveltekit'
import { error, invalid } from '@sveltejs/kit'
export const actions: Actions = {
createPost: withAuth(async ({ session, getSupabaseClient, request }) => {
if (!session.user) {
// the user is not signed in
throw error(403, { message: 'Unauthorized' })
}
// we are save, let the user create the post
const formData = await request.formData()
const content = formData.get('content')
const { error: createPostError, data: newPost } = await getSupabaseClient()
.from('posts')
.insert({ content })
if (createPostError) {
return invalid(500, {
supabaseErrorMessage: createPostError.message,
})
}
return {
newPost,
}
}),
}
```
If you try to submit a form with the action `?/createPost` without a valid session cookie, you will get a 403 error response.
## Saving and deleting the session
Use `saveSession` to save the session cookies:
```ts
import type { Actions } from './$types'
import { supabaseClient } from '$lib/db'
import { invalid, redirect } from '@sveltejs/kit'
import { saveSession } from '@supabase/auth-helpers-sveltekit/server'
export const actions: Actions = {
async signin({ request, cookies, url }) {
const formData = await request.formData()
const email = formData.get('email') as string
const password = formData.get('password') as string
const { data, error } = await supabaseClient.auth.api.signInWithEmail(
email,
password,
{
redirectTo: `${url.origin}/logging-in`,
}
)
if (error || !data) {
if (error?.status === 400) {
return invalid(400, {
error: 'Invalid credentials',
values: {
email,
},
})
}
return invalid(500, {
error: 'Server error. Try again later.',
values: {
email,
},
})
}
saveSession(cookies, data)
throw redirect(303, '/dashboard')
},
}
```
Use `deleteSession` to delete the session cookies:
```ts
import type { Actions } from './$types'
import { deleteSession } from '@supabase/auth-helpers-sveltekit/server'
import { redirect } from '@sveltejs/kit'
export const actions: Actions = {
async logout({ cookies }) {
deleteSession(cookies)
throw redirect(303, '/')
},
}
```
## Custom session namespace
If you want to use something other than `locals.session` and `$page.data.session`, update the types and create three helper functions:
```ts title="src/app.d.ts"
declare namespace App {
interface Locals {
mySupabaseSession: import('@supabase/auth-helpers-sveltekit').SupabaseSession
}
interface PageData {
mySupabaseSession: import('@supabase/auth-helpers-sveltekit').SupabaseSession
}
}
```
```ts title="src/hooks.server.ts"
setupSupabaseServer({
supabaseClient,
cookieOptions: {
secure: !dev,
},
// --- change location within locals ---
getSessionFromLocals: (locals) => locals.mySupabaseSession,
setSessionToLocals: (locals, session) => (locals.mySupabaseSession = session),
})
```
```ts title="src/lib/db.ts"
setupSupabaseClient({
supabaseClient,
// --- change location within pageData ---
getSessionFromPageData: (data) => data.mySupabaseSession,
})
```
## Migrate from 0.6.11 and below to 0.7.0 {#migration}
There are numerous breaking changes in the latest 0.7.0 version of this library.
### Environment variable prefix
The environment variable prefix is now `PUBLIC_` instead of `VITE_` (e.g., `VITE_SUPABASE_URL` is now `PUBLIC_SUPABASE_URL`).
### Set up the Supabase client {#migration-set-up-supabase-client}
<Tabs
groupId="version"
values={[
{label: '0.6.11 and below', value: 'older'},
{label: '0.7.0', value: 'latest'},
]}>
<TabItem value="older">
```js title="src/lib/db.ts"
import { createSupabaseClient } from '@supabase/auth-helpers-sveltekit';
const { supabaseClient } = createSupabaseClient(
import.meta.env.VITE_SUPABASE_URL as string,
import.meta.env.VITE_SUPABASE_ANON_KEY as string
);
export { supabaseClient };
```
</TabItem>
<TabItem value="latest">
```js title="src/lib/db.ts"
import { createClient } from '@supabase/supabase-js'
import { setupSupabaseHelpers } from '@supabase/auth-helpers-sveltekit'
import { dev } from '$app/environment'
import { env } from '$env/dynamic/public'
// or use the static env
// import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public';
export const supabaseClient = createClient(
env.PUBLIC_SUPABASE_URL,
env.PUBLIC_SUPABASE_ANON_KEY,
{
persistSession: false,
autoRefreshToken: false,
}
)
setupSupabaseHelpers({
supabaseClient,
cookieOptions: {
secure: !dev,
},
})
```
</TabItem>
</Tabs>
### Initialize the client {#migration-initialize-client}
<Tabs
groupId="version"
values={[
{label: '0.6.11 and below', value: 'older'},
{label: '0.7.0', value: 'latest'},
]}>
<TabItem value="older">
```html title="src/routes/__layout.svelte"
<script>
import { session } from '$app/stores'
import { supabaseClient } from '$lib/db'
import { SupaAuthHelper } from '@supabase/auth-helpers-svelte'
</script>
<SupaAuthHelper {supabaseClient} {session}>
<slot />
</SupaAuthHelper>
```
</TabItem>
<TabItem value="latest">
The `@supabase/auth-helpers-svelte` library is no longer required as the `@supabase/auth-helpers-sveltekit` library handles all the client-side code.
```html title="src/routes/+layout.svelte"
<script lang="ts">
// make sure the supabase instance is initialized on the client
import '$lib/db'
import { startSupabaseSessionSync } from '@supabase/auth-helpers-sveltekit'
import { page } from '$app/stores'
import { invalidateAll } from '$app/navigation'
// this sets up automatic token refreshing
startSupabaseSessionSync({
page,
handleRefresh: () => invalidateAll(),
})
</script>
<slot />
```
</TabItem>
</Tabs>
### Set up hooks {#migration-set-up-hooks}
<Tabs
groupId="version"
values={[
{label: '0.6.11 and below', value: 'older'},
{label: '0.7.0', value: 'latest'},
]}>
<TabItem value="older">
```ts title="src/hooks.ts"
import { handleAuth } from '@supabase/auth-helpers-sveltekit'
import type { GetSession, Handle } from '@sveltejs/kit'
import { sequence } from '@sveltejs/kit/hooks'
export const handle: Handle = sequence(...handleAuth())
export const getSession: GetSession = async (event) => {
const { user, accessToken, error } = event.locals
return {
user,
accessToken,
error,
}
}
```
</TabItem>
<TabItem value="latest">
```ts title="src/hooks.server.ts"
// make sure the supabase instance is initialized on the server
import '$lib/db'
import { dev } from '$app/environment'
import { auth } from '@supabase/auth-helpers-sveltekit/server'
export const handle = auth()
```
**Optional** _if using additional handle methods_
```ts title="src/hooks.server.ts"
// make sure the supabase instance is initialized on the server
import '$lib/db'
import { dev } from '$app/environment'
import { auth } from '@supabase/auth-helpers-sveltekit/server'
import { sequence } from '@sveltejs/kit/hooks'
export const handle = sequence(auth(), yourHandler)
```
</TabItem>
</Tabs>
### Typings {#migration-typings}
<Tabs
groupId="version"
values={[
{label: '0.6.11 and below', value: 'older'},
{label: '0.7.0', value: 'latest'},
]}>
<TabItem value="older">
```ts title="src/app.d.ts"
/// <reference types="@sveltejs/kit" />
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
declare namespace App {
interface UserSession {
user: import('@supabase/supabase-js').User
accessToken?: string
}
interface Locals extends UserSession {
error: import('@supabase/supabase-js').ApiError
}
interface Session extends UserSession {}
// interface Platform {}
// interface Stuff {}
}
```
</TabItem>
<TabItem value="latest">
```ts title="src/app.d.ts"
/// <reference types="@sveltejs/kit" />
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
// and what to do when importing types
declare namespace App {
interface Locals {
session: import('@supabase/auth-helpers-sveltekit').SupabaseSession
}
interface PageData {
session: import('@supabase/auth-helpers-sveltekit').SupabaseSession
}
// interface Error {}
// interface Platform {}
}
```
</TabItem>
</Tabs>
### Check the user on the client
<Tabs
groupId="version"
values={[
{label: '0.6.11 and below', value: 'older'},
{label: '0.7.0', value: 'latest'},
]}>
<TabItem value="older">
```html title="src/routes/index.svelte"
<script>
import { session } from '$app/stores'
</script>
{#if !$session.user}
<h1>I am not logged in</h1>
{:else}
<h1>Welcome {$session.user.email}</h1>
<p>I am logged in!</p>
{/if}
```
</TabItem>
<TabItem value="latest">
```html title="src/routes/+page.svelte"
<script>
import { page } from '$app/stores'
</script>
{#if !$page.data.session.user}
<h1>I am not logged in</h1>
{:else}
<h1>Welcome {$page.data.session.user.email}</h1>
<p>I am logged in!</p>
{/if}
```
</TabItem>
</Tabs>
### withPageAuth
<Tabs
groupId="version"
values={[
{label: '0.6.11 and below', value: 'older'},
{label: '0.7.0', value: 'latest'},
]}>
<TabItem value="older">
```html title="src/routes/protected-route.svelte"
<script lang="ts" context="module">
import {
supabaseServerClient,
withPageAuth,
} from '@supabase/auth-helpers-sveltekit'
import type { Load } from './__types/protected-page'
export const load: Load = async ({ session }) =>
withPageAuth(
{
redirectTo: '/',
user: session.user,
},
async () => {
const { data } = await supabaseServerClient(session.accessToken)
.from('test')
.select('*')
return { props: { data, user: session.user } }
}
)
</script>
<script>
export let data
export let user
</script>
<div>Protected content for {user.email}</div>
<p>server-side fetched data with RLS:</p>
<pre>{JSON.stringify(data, null, 2)}</pre>
<p>user:</p>
<pre>{JSON.stringify(user, null, 2)}</pre>
```
</TabItem>
<TabItem value="latest">
```html title="src/routes/protected-route/+page.svelte"
<script lang="ts">
import type { PageData } from './$types'
export let data: PageData
$: ({ tableData, user } = data)
</script>
<div>Protected content for {user.email}</div>
<p>server-side fetched data with RLS:</p>
<pre>{JSON.stringify(tableData, null, 2)}</pre>
<p>user:</p>
<pre>{JSON.stringify(user, null, 2)}</pre>
```
```ts title="src/routes/protected-route/+page.ts"
import { withAuth } from '@supabase/auth-helpers-sveltekit'
import { redirect } from '@sveltejs/kit'
import type { PageLoad } from './$types'
export const load: PageLoad = withAuth(
async ({ session, getSupabaseClient }) => {
if (!session.user) {
throw redirect(303, '/')
}
const { data: tableData } = await getSupabaseClient()
.from('test')
.select('*')
return { tableData, user: session.user }
}
)
```
</TabItem>
</Tabs>
### withApiAuth
<Tabs
groupId="version"
values={[
{label: '0.6.11 and below', value: 'older'},
{label: '0.7.0', value: 'latest'},
]}>
<TabItem value="older">
```ts title="src/routes/api/protected-route.ts"
import {
supabaseServerClient,
withApiAuth,
} from '@supabase/auth-helpers-sveltekit'
import type { RequestHandler } from './__types/protected-route'
interface TestTable {
id: string
created_at: string
}
interface GetOutput {
data: TestTable[]
}
export const GET: RequestHandler<GetOutput> = async ({ locals, request }) =>
withApiAuth({ user: locals.user }, async () => {
// Run queries with RLS on the server
const { data } = await supabaseServerClient(request)
.from('test')
.select('*')
return {
status: 200,
body: { data },
}
})
```
</TabItem>
<TabItem value="latest">
```ts title="src/routes/api/protected-route/+server.ts"
import type { RequestHandler } from './$types';
import { withAuth } from '@supabase/auth-helpers-sveltekit';
import { json, redirect } from '@sveltejs/kit';
interface TestTable {
id: string;
created_at: string;
}
export const GET: RequestHandler = withAuth(async ({ session, getSupabaseClient }) => {
if (!session.user) {
throw redirect(303, '/');
}
const { data } = await getSupabaseClient()
.from<TestTable>('test')
.select('*');
return json({ data });
);
```
</TabItem>
</Tabs>
## Additional Links
- [Auth Helpers Source code](https://github.com/supabase/auth-helpers)
- [SvelteKit example](https://github.com/supabase/auth-helpers/tree/main/examples/sveltekit)
- [SvelteKit Email/Password example](https://github.com/supabase/auth-helpers/tree/main/examples/sveltekit-email-password)
- [SvelteKit Magiclink example](https://github.com/supabase/auth-helpers/tree/main/examples/sveltekit-magic-link)
@@ -1,86 +0,0 @@
---
id: auth-keycloak
title: 'Login with Keycloak'
description: Add Keycloak OAuth to your Supabase project
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
To enable Keycloak Auth for your project, you need to set up an Keycloak OAuth application and add the application credentials to your Supabase Dashboard.
## Overview
To get started with Keycloak, you can run it in a docker container with: `docker run -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin -p 8080:8080 jboss/keycloak:latest`
This guide will be assuming that you are running keycloak in a docker container as described in the command above.
Keycloak OAuth consists of five broad steps:
- Create a new client in your specified keycloak realm.
- Obtain the `issuer` from the "OpenID Endpoint Configuration". This will be used as the `Keycloak URL`.
- Ensure that the new client has the "Client Protocol" set to "openid-connect" and the "Access Type" is set to "confidential".
- The `Client ID` of the client created will be used as the `client id`.
- Obtain the `Secret` from the credentials tab which will be used as the `client secret`.
- Add the callback url of your application to your allowlist.
## Access your Keycloak Admin console
- Login by visiting [`http://localhost:8080`](http://localhost:8080) and clicking on "Administration Console".
## Create a Keycloak Realm
- Once you've logged in to the Keycloak console, you can add a realm from the side panel. The default realm should be named "Master".
- After you've added a new realm, you can retrieve the `issuer` from the "OpenID Endpoint Configuration" endpoint. The `issuer` will be used as the `Keycloak URL`.
- You can find this endpoint from the realm settings under the "General Tab" or visit [`http://localhost:8080/realms/my_realm_name/.well-known/openid-configuration`](http://localhost:8080/realms/my_realm_name/.well-known/openid-configuration)
![Add a Keycloak Realm.](/img/guides/auth-keycloak/keycloak-create-realm.png)
## Create a Keycloak Client
The "Client ID" of the created client will serve as the `client_id` when you make API calls to authenticate the user.
![Add a Keycloak client](/img/guides/auth-keycloak/keycloak-add-client.png)
## Client Settings
After you've created the client successfully, ensure that you set the following settings:
1. The "Client Protocol" should be set to "openid-connect".
2. The "Access Type" should be set to "confidential".
3. The "Valid Redirect URIs" should be set to: `https://<project-ref>.supabase.co/auth/v1/callback`.
![Obtain the client id, set the client protocol and access type](/img/guides/auth-keycloak/keycloak-client-id.png)
![Set redirect uri](/img/guides/auth-keycloak/keycloak-redirect-uri.png)
## Obtain the Client Secret
This will serve as the `client_secret` when you make API calls to authenticate the user.
Under the "Credentials" tab, the `Secret` value will be used as the `client secret`.
![Obtain the client secret](/img/guides/auth-keycloak/keycloak-client-secret.png)
## Add login code to your client app
When your user signs in, call [signInWithOAuth()](/docs/reference/javascript/auth-signinwithoauth) with `keycloak` as the `provider`:
```js
async function signInWithKeycloak() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'keycloak',
})
}
```
When your user signs out, call [signOut()](/docs/reference/javascript/auth-signout) to remove them from the browser session and any objects from localStorage:
```js
async function signout() {
const { error } = await supabase.auth.signOut()
}
```
## Resources
- You can find the keycloak openid endpoint configuration under the realm settings.
![Keycloak OpenID Endpoint Configuration](/img/guides/auth-keycloak/keycloak-openid-endpoint-config.png)
@@ -1,93 +0,0 @@
---
id: auth-linkedin
title: 'Login with LinkedIn'
description: Add LinkedIn OAuth to your Supabase project
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
To enable LinkedIn Auth for your project, you need to set up a LinkedIn OAuth application and add the application credentials to your Supabase Dashboard.
## Overview
Setting up LinkedIn logins for your application consists of 3 parts:
- Create and configure a LinkedIn Project and App on the [LinkedIn Developer Dashboard](https://www.linkedin.com/developers/apps).
- Add your LinkedIn `client_id` and `client_secret` to your [Supabase Project](https://app.supabase.com).
- Add the login code to your [Supabase JS Client App](https://github.com/supabase/supabase-js).
## Access your LinkedIn Developer account
- Go to [LinkedIn Developer Dashboard](https://www.linkedin.com/developers/apps).
- Log in (if necessary.)
![LinkedIn Developer Portal](/img/guides/auth-linkedin/linkedin_developers_page.png)
## Find your callback URL
The next step requires a callback URL, which looks like this:
`https://<project-ref>.supabase.co/auth/v1/callback`
- Go to your [Supabase Project Dashboard](https://app.supabase.com).
- Click on the `Settings` icon at the bottom of the left sidebar.
- Click on `API` in the list.
- Under Config / URL you'll find your API URL, you can click `Copy` to copy it to the clipboard.
- Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`.
<video width="99%" muted playsInline controls="true">
<source
src="/docs/videos/api/api-url-and-key.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
## Create a LinkedIn OAuth app
- Go to [LinkedIn Developer Dashboard](https://www.linkedin.com/developers/apps).
- Click on `Create App` at the top right
- Enter your `LinkedIn Page` and `App Logo`
- Save your app
- Click `Auth` from the top menu
- Add your `Redirect URL` to the `Authorized Redirect URLs for your app` section
- Copy and save your newly-generated `Client ID`
- Copy and save your newly-generated `Client Secret`
## Enter your LinkedIn credentials into your Supabase Project
- Go to your [Supabase Project Dashboard](https://app.supabase.com).
- In the left sidebar, click the `Authentication` icon (near the top).
- Click `Settings` from the list to go to the `Authentication Settings` page.
- Enter the final (hosted) URL of your app under `Site URL` (this is important).
- Under `External OAuth Providers` turn `LinkedIn Enabled` to ON.
- Enter your `client_id` and `client_secret` saved in the previous step.
- Click `Save`.
## Add login code to your client app
When your user signs in, call [signInWithOAuth()](/docs/reference/javascript/auth-signinwithoauth) with `linkedin` as the `provider`:
```js
async function signInWithLinkedIn() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'linkedin',
})
}
```
When your user signs out, call [signOut()](/docs/reference/javascript/auth-signout) to remove them from the browser session and any objects from localStorage:
```js
async function signout() {
const { error } = await supabase.auth.signOut()
}
```
## Resources
- [Supabase Account - Free Tier OK](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [LinkedIn Developer Dashboard](https://api.LinkedIn.com/apps)
@@ -1,98 +0,0 @@
---
id: auth-magic-link
title: 'Login With Magic Link'
description: Use Supabase to authenticate and authorize your users using magic links.
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
Magic links are a form of passwordless logins where users click on a link sent to their email address to log in to their accounts.
Magic links only work with email addresses. By default, a user can only request a magic link once every 60 seconds.
## Overview
Setting up Magic Link logins for your Supabase application.
- Add Magic Link authenticator to your [Supabase Project](https://app.supabase.com)
- Add the login code to your application - [JavaScript](https://github.com/supabase/supabase-js) | [Flutter](https://github.com/supabase/supabase-flutter)
## Add Magic Link into your Supabase Project
1. Go to the [Authentication Settings](https://app.supabase.com/project/_/auth/settings) page in the Dashboard.
1. For **Site URL**, enter the final (hosted) URL of your app.
1. Under Auth Providers, **enable email provider**.
## Add login code to your client app
<Tabs
defaultValue="js"
groupId="guides/auth"
values={[{ label: 'JavaScript', value: 'js' }, { label: 'Dart', value: 'dart' }]}
>
<TabItem value="js">
When your user signs in, call [signInWithOtp()](/docs/reference/javascript/auth-signinwithotp) with their email address:
```js
async function signInWithEmail() {
const { data, error } = await supabase.auth.signInWithOtp({
email: 'example@email.com',
})
}
```
</TabItem>
<TabItem value="dart">
When your user signs in, call [signIn()](/docs/reference/dart/auth-signinwithotp) with their email address:
```dart
Future<void> signInWithEmail() async {
final AuthResponse res = await supabase.auth.signinwithotp(email: 'example@email.com');
}
```
</TabItem>
</Tabs>
<Tabs
defaultValue="js"
groupId="guides/auth"
values={[{ label: 'JavaScript', value: 'js' }, { label: 'Dart', value: 'dart' }]}
>
<TabItem value="js">
When your user signs out, call [signOut()](/docs/reference/javascript/auth-signout) to remove them from the browser session and any objects from localStorage:
```js
async function signOut() {
const { error } = await supabase.auth.signOut()
}
```
</TabItem>
<TabItem value="dart">
When your user signs out, call [signOut()](/docs/reference/dart/auth-signout) to remove them from the browser session and any objects from localStorage:
```dart
Future<void> signOut() async {
await supabase.auth.signOut();
}
```
</TabItem>
</Tabs>
## Resources
- [Supabase Account - Free Tier OK](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Supabase Flutter Client](https://github.com/supabase/supabase-flutter)
@@ -1,283 +0,0 @@
---
id: auth-messagebird
title: Phone Auth with MessageBird
description: How to set up and use Mobile OTP with MessageBird and Supabase.
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
## Overview
In this guide we'll show you how to authenticate your users with SMS based OTP (One-Time Password) tokens.
There are two reasons to use Supabase SMS OTP tokens:
- You want users to log in with mobile + password, and the mobile should be verified via SMS
- You want users to log in with mobile ONLY (i.e. passwordless login)
We'll cover:
- [Finding your MessageBird credentials](#finding-your-messagebird-credentials)
- [Using OTP with password based logins](#using-otp-with-password-based-logins)
- [Using OTP as a passwordless sign-in mechanism](#using-otp-as-a-passwordless-sign-in-mechanism)
What you'll need:
- A MessageBird account (sign up here: https://dashboard.messagebird.com/en/sign-up)
- A Supabase project (create one here: https://app.supabase.com)
- A mobile phone capable of receiving SMS
## Steps
### Finding your MessageBird credentials
Start by logging into your MessageBird account and verify the mobile number you'll be using to test with: https://dashboard.messagebird.com/en/getting-started/sms
This is the number that will be receiving the SMS OTPs.
![Verify your own phone number](/img/guides/auth-messagebird/1.png)
![Get your API Keys](/img/guides/auth-messagebird/2.png)
Navigate to the [dashboard settings](https://dashboard.messagebird.com/en/settings/sms) to set the default originator. The messagebird originator is the name or number from which the message is sent.
For more information, you can refer to the messagebird article on choosing an originator [here](https://support.messagebird.com/hc/en-us/articles/115002628665-Choosing-an-originator)
![Set the default originator](/img/guides/auth-messagebird/3.png)
You will need the following values to get started:
- Live API Key / Test API Key
- MessageBird originator
Now go to the Auth > Settings page in the Supabase dashboard (https://app.supabase.com/project/YOUR-PROJECT-REF/auth/settings).
You should see an option to enable Phone Signup.
![Enable Phone Sign-Up](/img/guides/auth-twilio/7.png)
Toggle it on, and copy the 2 values over from the messagebird dashboard. Click save.
Note: If you use the Test API Key, the OTP will not be delivered to the mobile number specified but messagebird will log the response in the dashboard.
If the Live API Key is used instead, the OTP will be delivered and there will be a deduction in your free credits.
<!-- TODO: Add screenshot of UI -->
Plugin MessageBird credentials
Now the backend should be setup, we can proceed to add our client-side code!
#### SMS custom template
The SMS message sent to a phone containing an OTP code can be customized. This is useful if you need to mention a brand name or display a website address.
Go to Auth > Templates page in the Supabase dashboard (https://app.supabase.com/project/YOUR-PROJECT-REF/auth/templates).
Use the variable `.Code` in the template to display the code.
### Using OTP with password based logins
In this use scenario we'll be using the user's mobile phone number as an alternative to an email address when signing up along with a password. You may want to think hard about the permanency of this however. It is not uncommon for mobile phone numbers to be recycled by phone networks when users cancel their phone contracts or move countries, therefore granting access to the user's account to whoever takes over the phone number in the future. Soon we'll add multi-factor auth, which will mitigate this risk, but for now you may want to give some thought to allowing your users to recover their account by some other means in an emergency.
Using supabase-js on the client you'll want to use the same `signUp` method that you'd use for email based sign ups, but with the `phone` param instead of the `email param`:
<Tabs
defaultValue="JS"
values={[
{label: 'JavaScript', value: 'JS'},
{label: 'HTTP', value: 'HTTP'},
]}>
<TabItem value="JS">
```js
let { user, error } = await supabase.auth.signUp({
phone: '+13334445555',
password: 'some-password',
})
```
</TabItem>
<TabItem value="HTTP">
```bash
curl -X POST 'https://cvwawazfelidkloqmbma.supabase.co/auth/v1/signup' \
-H "apikey: SUPABASE_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "+13334445555",
"password": "some-password"
}'
```
</TabItem>
</Tabs>
The user will now receive an SMS with a 6-digit pin that you will need to receive from them within 60-seconds before they can login to their account.
You should present a form to the user so they can input the 6 digit pin, then send it along with the phone number to `verifyOTP`:
<Tabs
defaultValue="JS"
values={[
{label: 'JavaScript', value: 'JS'},
{label: 'HTTP', value: 'HTTP'},
]}>
<TabItem value="JS">
```js
let { session, error } = await supabase.auth.verifyOTP({
phone: '+13334445555',
token: '123456',
})
```
</TabItem>
<TabItem value="HTTP">
```bash
curl -X POST 'https://cvwawazfelidkloqmbma.supabase.co/auth/v1/verify' \
-H "apikey: SUPABASE_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "sms",
"phone": "+13334445555",
"token": "123456"
}'
```
</TabItem>
</Tabs>
If successful the user will now be logged in and you should receive a valid session like:
```json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhdXRoZW50aWNhdGVkIiwiZXhwIjoxNjI3MjkxNTc3LCJzdWIiOiJmYTA2NTQ1Zi1kYmI1LTQxY2EtYjk1NC1kOGUyOTg4YzcxOTEiLCJlbWFpbCI6IiIsInBob25lIjoiNjU4NzUyMjAyOSIsImFwcF9tZXRhZGF0YSI6eyJwcm92aWRlciI6InBob25lIn0sInVzZXJfbWV0YWRhdGEiOnt9LCJyb2xlIjoiYXV0aGVudGljYXRlZCJ9.1BqRi0NbS_yr1f6hnr4q3s1ylMR3c1vkiJ4e_N55dhM",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "LSp8LglPPvf0DxGMSj-vaQ"
}
```
The access token can be sent in the Authorization header as a Bearer token for any CRUD operations on supabase-js. See our guide on [Row Level Security](/docs/guides/auth#row-level-security) for more info on restricting access on a user basis.
Also now that the mobile has been verified, the user can use the number and password to sign in without needing to verify their number each time:
<Tabs
defaultValue="JS"
values={[
{label: 'JavaScript', value: 'JS'},
{label: 'HTTP', value: 'HTTP'},
]}>
<TabItem value="JS">
```js
let { user, error } = await supabase.auth.signInWithPassword({
phone: '+13334445555',
password: 'some-password',
})
```
</TabItem>
<TabItem value="HTTP">
```bash
curl -X POST 'https://cvwawazfelidkloqmbma.supabase.co/auth/v1/token?grant_type=password' \
-H "apikey: SUPABASE_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "+13334445555",
"password": "some-password"
}'
```
</TabItem>
</Tabs>
### Using OTP as a passwordless sign-in mechanism
In this scenario you are granting your user's the ability to login to their account without needing to set a password on their account, all they have to do to log in is verify their mobile each time using the OTP.
In javascript we can use the `signIn` method with a single parameter: `phone`
<Tabs
defaultValue="JS"
values={[
{label: 'JavaScript', value: 'JS'},
{label: 'HTTP', value: 'HTTP'},
]}>
<TabItem value="JS">
```js
let { user, error } = await supabase.auth.signInWithOtp({
phone: '+13334445555',
})
```
</TabItem>
<TabItem value="HTTP">
```bash
curl -X POST 'https://cvwawazfelidkloqmbma.supabase.co/auth/v1/otp' \
-H "apikey: SUPABASE_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "+13334445555"
}'
```
</TabItem>
</Tabs>
The second step is the same as the previous section, you need to collect the 6-digit pin from the user and pass it along with their phone number to the verify method:
<Tabs
defaultValue="JS"
values={[
{label: 'JavaScript', value: 'JS'},
{label: 'HTTP', value: 'HTTP'},
]}>
<TabItem value="JS">
```js
let { session, error } = await supabase.auth.verifyOTP({
phone: '+13334445555',
token: '123456',
})
```
</TabItem>
<TabItem value="HTTP">
```bash
curl -X POST 'https://cvwawazfelidkloqmbma.supabase.co/auth/v1/verify' \
-H "apikey: SUPABASE_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "sms",
"phone": "+13334445555",
"token": "123456"
}'
```
</TabItem>
</Tabs>
and the response should also be the same as above:
```json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhdXRoZW50aWNhdGVkIiwiZXhwIjoxNjI3MjkxNTc3LCJzdWIiOiJmYTA2NTQ1Zi1kYmI1LTQxY2EtYjk1NC1kOGUyOTg4YzcxOTEiLCJlbWFpbCI6IiIsInBob25lIjoiNjU4NzUyMjAyOSIsImFwcF9tZXRhZGF0YSI6eyJwcm92aWRlciI6InBob25lIn0sInVzZXJfbWV0YWRhdGEiOnt9LCJyb2xlIjoiYXV0aGVudGljYXRlZCJ9.1BqRi0NbS_yr1f6hnr4q3s1ylMR3c1vkiJ4e_N55dhM",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "LSp8LglPPvf0DxGMSj-vaQ"
}
```
The user does not have a password therefore will need to sign in via this method each time they want to access your service.
## Resources
- [MessageBird Signup](https://dashboard.messagebird.com/en/sign-up)
- [Supabase Dashboard](https://app.supabase.com)
- [Supabase Row Level Security](/docs/guides/auth#row-level-security)
@@ -1,625 +0,0 @@
---
id: auth-mfa
title: 'Multi-Factor Authentication'
description: Add an additional layer of security to your apps with Supabase Auth multi-factor authentication.
---
import { Mermaid } from 'mdx-mermaid/Mermaid';
:::note
Multi-Factor Authentication is in early access preview only. Although we
believe it is production ready, APIs and some behavior may change based on
feedback we receive in the preview period.
:::
Multi-factor authentication (MFA), sometimes called two-factor
authentication (2FA), adds an additional layer of security to your
application by verifying their identity through
additional verification steps.
It is considered a best practice to use MFA for your applications.
Users with weak passwords or compromised social login accounts are
prone to malicious account takeovers. These can be prevented with
MFA because they require the user to provide proof of
both of these:
- Something they know.
Password, or access to a social-login account.
- Something they have.
Access to an authenticator app (a.k.a. TOTP), mobile phone or recovery code.
## Overview
Supabase Auth implements only Time-based One Time Factor(TOTP) multi-factor authentication. This type of
multi-factor authentication uses a timed one-time password generated from an
authenticator app in the control of users.
Applications using MFA require two important flows:
1. **Enrollment flow.**
This lets users set up and control MFA in your app.
2. **Authentication flow.**
This lets users sign in using any factors after the conventional login step.
Supabase Auth provides:
- **Enrollment API** - build rich user interfaces for adding and removing factors.
- **Challenge and Verify APIs** - securely verify that the user has access to a factor.
- **List Factors API** - build rich user interfaces for signing in with additional factors.
Below is a flow chart illustrating how these APIs work together to enable MFA
features in your app.
<Mermaid chart={`
graph TD;
InitS((Setup flow)) --> SAAL1[/Session is AAL1/] --> Enroll[Enroll API] --> ShowQR[Show QR code] --> Scan([User: Scan QR code in authenticator]) --> Enter([User: Enter code]) --> Verify[Challenge + Verify API] --> Check{{Is code correct?}}
Check -->|Yes| AAL2[/Upgrade to AAL2/] --> Done((Done))
Check -->|No| Enter
InitA((Login flow)) --> SignIn([User: Sign-in]) --> AAL1[/Upgrade to AAL1/] --> ListFactors[List Factors API]
ListFactors -->|1 or more factors| OpenAuth([User: Open authenticator]) --> Enter
ListFactors -->|0 factors| Setup[[Setup flow]]
`} />
These sets of APIs let you control the MFA experience that works for you. You
can create flows where MFA is optional, mandatory for all or only specific
groups of users.
Once users have enrolled or signed-in with a factor, Supabase Auth adds
additional metadata to the user's access token (JWT) that your application can
use to allow or deny access.
This information is represented by an [Authenticator Assurance
Level](https://pages.nist.gov/800-63-3-Implementation-Resources/63B/AAL/), a
standard measure about the assurance Supabase Auth has of the user's identity
for that particular session. There are two levels recognized today:
1. **Assurance Level 1: `aal1`**
Means that the user's identity was verified using a conventional login method
such as email+password, magic link, one-time password, phone auth or social
login.
2. **Assurance Level 2: `aal2`**
Means that the user's identity was additionally verified using at least one
second factor, such as a TOTP code.
This assurance level is encoded in the `aal` claim in the JWT associated with
the user. By decoding this value you can create custom authorization rules in
your frontend, backend and database that will enforce the MFA policy that works
for your application. JWTs without an `aal` claim are at the `aal1` level.
## Adding to your app
Adding MFA to your app involves these three steps:
1. **Add enrollment flow.**
You need to provide a UI within your app that your users will be able to set-up
MFA in. You can add this right after sign-up, or as part of a separate flow in
the settings portion of your app.
2. **Add challenge step to login.**
If a user has set-up MFA, your app's login flow needs to present a challenge
screen to the user asking them to prove they have access to the additional
factor.
3. **Enforce rules for MFA logins.**
Once your users have a way to enroll and log in with MFA, you need to enforce
authorization rules across your app: on the frontend, backend, API servers or
Row-Level Security policies.
### Add enrollment flow
An enrollment flow provides a UI for users to set up additional authentication factors.
Most applications add the enrollment flow in two places within their app:
1. Right after login or sign up.
This lets users quickly set up MFA immediately after they log in or create an
account. We recommend encouraging all users to set up MFA if that makes sense
for your application. Many applications offer this as an opt-in step in an
effort to reduce onboarding friction.
2. From within a settings page.
Allows users to set up, disable or modify their MFA settings.
We recommend building one generic flow that you can reuse in both cases with
minor modifications.
Enrolling a factor for use with MFA takes three steps:
1. Call `supabase.auth.mfa.enroll()`.
This method returns a QR code and a secret. Display the QR
code to the user and ask them to scan it with their authenticator application.
If they are unable to scan the QR code, show the secret in plain text which
they can type or paste into their authenticator app.
2. Calling the `supabase.auth.mfa.challenge()` API.
This prepares Supabase Auth to accept a verification code from the user
and returns a challenge ID.
3. Calling the `supabase.auth.mfa.verify()` API.
This verifies that the user has indeed added the secret from step (1) into
their app and is working correctly. If the verification succeeds, the factor
immediately becomes active for the user account. If not, you should repeat
steps 2 and 3.
#### Example: React
Below is an example that creates a new `EnrollMFA` component that illustrates
the important pieces of the MFA enrollment flow.
- When the component appears on screen, the `supabase.auth.mfa.enroll()` API is
called once to start the process of enrolling a new factor for the current
user.
- This API returns a QR code in the SVG format, which is shown on screen using
a normal `<img>` tag by encoding the SVG as a data URL.
- Once the user has scanned the QR code with their authenticator app, they
should enter the verification code within the `verifyCode` input field and
click on `Enable`.
- A challenge is created using the `supabase.auth.mfa.challenge()` API and the
code from the user is submitted for verification using the
`supabase.auth.mfa.verify()` challenge.
- `onEnabled` is a callback that notifies the other components that enrollment
has completed.
- `onCancelled` is a callback that notifies the other components that the user
has clicked the `Cancel` button.
```tsx
/**
* EnrollMFA shows a simple enrollment dialog. When shown on screen it calls
* the `enroll` API. Each time a user clicks the Enable button it calls the
* `challenge` and `verify` APIs to check if the code provided by the user is
* valid.
* When enrollment is successful, it calls `onEnrolled`. When the user clicks
* Cancel the `onCancelled` callback is called.
*/
export function EnrollMFA({
onEnrolled,
onCancelled,
}: {
onEnrolled: () => void;
onCancelled: () => void;
}) {
const [factorId, setFactorId] = useState("");
const [qr, setQR] = useState(""); // holds the QR code image SVG
const [verifyCode, setVerifyCode] = useState(""); // contains the code entered by the user
const [error, setError] = useState(""); // holds an error message
const onEnableClicked = () => {
setError("");
(async () => {
const challenge = await supabase.auth.mfa.challenge({ factorId });
if (challenge.error) {
setError(challenge.error.message);
throw challenge.error;
}
const challengeId = challenge.data.id;
const verify = await supabase.auth.mfa.verify({
factorId,
challengeId,
code: verifyCode,
});
if (verify.error) {
setError(verify.error.message);
throw verify.error;
}
onEnrolled();
})();
};
useEffect(() => {
(async () => {
const { data, error } = await supabase.auth.mfa.enroll({
factorType: "totp",
});
if (error) {
throw error;
}
setFactorId(data.id);
// Supabase Auth returns an SVG QR code which you can convert into a data
// URL that you can place in an <img> tag.
setQR(data.totp.qr_code);
})();
}, []);
return (
<>
{error && <div className="error">{error}</div>}
<img src={qr} />
<input
type="text"
value={verifyCode}
onChange={(e) => setVerifyCode(e.target.value.trim())}
/>
<input type="button" value="Enable" onClick={onEnableClicked} />
<input type="button" value="Cancel" onClick={onCancelled} />
</>
);
}
```
### Add challenge step to login
Once a user has logged in via their first factor (email+password, magic link,
one time password, social login...) you need to perform a check if any
additional factors need to be verified.
This can be done by using the
`supabase.auth.mfa.getAuthenticatorAssuranceLevel()` API. When the user signs
in and is redirected back to your app, you should call this method to extract
the user's current and next authenticator assurance level (AAL).
Therefore if you receive a `currentLevel` which is `aal1` but a `nextLevel`
of `aal2`, the user should be given the option to go through MFA.
Below is a table that explains the combined meaning.
| Current Level | Next Level | Meaning |
| -------------:|:---------- |:------------------------------------------ |
| `aal1` | `aal1` | User does not have MFA enrolled. |
| `aal1` | `aal2` | User has an MFA factor enrolled but has not verified it. |
| `aal2` | `aal2` | User has verified their MFA factor. |
| `aal2` | `aal1` | User has disabled their MFA factor. (Stale JWT.) |
#### Example: React
Adding the challenge step to login depends heavily on the architecture of your
app. However, a fairly common way to structure React apps is to have a large
component (often named `App`) which contains most of the authenticated
application logic.
This example will wrap this component with logic that will show an MFA
challenge screen if necessary, before showing the full application. This is
illustrated in the `AppWithMFA` example below.
```tsx
function AppWithMFA() {
const [readyToShow, setReadyToShow] = useState(false);
const [showMFAScreen, setShowMFAScreen] = useState(false);
useEffect(() => {
(async () => {
try {
const { data, error } =
await supabase.auth.mfa.getAuthenticatorAssuranceLevel();
if (error) {
throw error;
}
console.log(data);
if (data.nextLevel === "aal2" && data.nextLevel !== data.currentLevel) {
setShowMFAScreen(true);
}
} finally {
setReadyToShow(true);
}
})();
}, []);
if (readyToShow) {
if (showMFAScreen) {
return <AuthMFA />;
}
return <App />;
}
return <></>;
}
```
- `supabase.auth.mfa.getAuthenticatorAssuranceLevel()` does return a promise.
Don't worry, this is a very fast method (microseconds) as it rarely uses the
network.
- `readyToShow` only makes sure the AAL check completes before showing any
application UI to the user.
- If the current level can be upgraded to the next one, the MFA screen is
shown.
- Once the challenge is successful, the `App` component is finally rendered on
screen.
Below is the component that implements the challenge and verify logic.
```tsx
function AuthMFA() {
const [verifyCode, setVerifyCode] = useState("");
const [error, setError] = useState("");
const onSubmitClicked = () => {
setError("");
(async () => {
const factors = await supabase.auth.mfa.listFactors();
if (factors.error) {
throw factors.error;
}
const totpFactor = factors.data.totp[0];
if (!totpFactor) {
throw new Error("No TOTP factors found!");
}
const factorId = totpFactor.id;
const challenge = await supabase.auth.mfa.challenge({ factorId });
if (challenge.error) {
setError(challenge.error.message);
throw challenge.error;
}
const challengeId = challenge.data.id;
const verify = await supabase.auth.mfa.verify({
factorId,
challengeId,
code: verifyCode,
});
if (verify.error) {
setError(verify.error.message);
throw verify.error;
}
})();
};
return (
<>
<div>Please enter the code from your authenticator app.</div>
{error && <div className="error">{error}</div>}
<input
type="text"
value={verifyCode}
onChange={(e) => setVerifyCode(e.target.value.trim())}
/>
<input type="button" value="Submit" onClick={onSubmitClicked} />
</>
);
}
```
- You can extract the available MFA factors for the user by calling
`supabase.auth.mfa.listFactors()`. Don't worry this method is also very quick
and rarely uses the network.
- If `listFactors()` returns more than one factor (or of a different type) you
should present the user with a choice. For simplicity this is not shown in
the example.
- Each time the user presses the "Submit" button a new challenge is created for
the chosen factor (in this case the first one) and it is immediately
verified. Any errors are displayed to the user.
- On successful verification, the client library will refresh the session in
the background automatically and finally call the `onSuccess` callback, which
will show the authenticated `App` component on screen.
### Enforce rules for MFA logins
Adding MFA to your app's UI does not in-and-of-itself offer a higher level of
security to your users. You also need to enforce the MFA rules in your
application's database, APIs and server-side rendering.
Depending on your application's needs, there are three ways you can choose to
enforce MFA.
1. **Enforce for all users (new and existing).**
Any user account will have to enroll MFA to continue using your app.
The application will not allow access without going through MFA first.
2. **Enforce for new users only.**
Only new users will be forced to enroll MFA, while old users will be encouraged
to do so.
The application will not allow access for new users without going through MFA
first.
3. **Enforce only for users that have opted-in.**
Users that want MFA can enroll in it and the application will not allow access
without going through MFA first.
#### Database
Your app should sufficiently deny or allow access to tables or rows based on
the user's current and possible authenticator levels.
:::warning
PostgreSQL has two types of policies: permissive and restrictive. This guide
uses restrictive policies. Make sure you don't omit the `as restrictive`
clause.
:::
##### Enforce for all users (new and existing)
If your app falls under this case, this is a template Row Level Security policy
you can apply to all your tables:
```sql
create policy "Policy name."
on table_name
as restrictive
to authenticated
using (auth.jwt()->>'aal' = 'aal2');
```
- Here the policy will not accept any JWTs with an `aal` claim other than
`aal2`, which is the highest authenticator assurance level.
- **Using `as restrictive` ensures this policy will restrict all commands on the
table regardless of other policies!**
##### Enforce for new users only
If your app falls under this case, the rules get more complex. User accounts
created past a certain timestamp must have a `aal2` level to access the
database.
```sql
create policy "Policy name."
on table_name
as restrictive -- very important!
to authenticated
using
(array[auth.jwt()->>'aal'] <@ (
select
case
when created_at >= '2022-12-12T00:00:00Z' then array['aal2']
else array['aal1', 'aal2', NULL]
end as aal
from auth.users
where auth.uid() = id));
```
- The policy will accept both `aal1` and `aal2` for users with a `created_at`
timestamp prior to 12th December 2022 at 00:00 UTC, but will only accept
`aal2` for all other timestamps.
- The `<@` operator is PostgreSQL's ["contained in"
operator.](https://www.postgresql.org/docs/current/functions-array.html)
- `NULL` appears because some JWTs originating from prior to the introduction
of MFA in Supabase Auth will not contain an `aal` claim.
- **Using `as restrictive` ensures this policy will restrict all commands on the
table regardless of other policies!**
##### Enforce only for users that have opted-in
Users that have enrolled MFA on their account are expecting that your
application only works for them if they've gone through MFA.
```sql
create policy "Policy name."
on table_name
as restrictive -- very important!
to authenticated
using (
array[auth.jwt()->>'aal'] <@ (
select
case
when count(id) > 0 then array['aal2']
else array['aal1', 'aal2', NULL]
end as aal
from auth.mfa_factors
where auth.uid() = user_id and status = 'verified'
));
```
- The policy will only accept only `aal2` when the user has at least one MFA
factor verified.
- Otherwise, it will accept both `aal1` and `aal2`.
- The `<@` operator is PostgreSQL's ["contained in"
operator.](https://www.postgresql.org/docs/current/functions-array.html)
- `NULL` appears because some JWTs originating from prior to the introduction
of MFA in Supabase Auth will not contain an `aal` claim.
- **Using `as restrictive` ensures this policy will restrict all commands on the
table regardless of other policies!**
### Server-Side Rendering
:::tip
When using the Supabase JavaScript library in a server-side rendering context,
make sure you always create a new object for each request! This will prevent
you from accidentally rendering and serving content belonging to different
users.
:::
It is possible to enforce MFA on the Server-Side Rendering level. However, this
can be tricky do to well.
You can use the `supabase.auth.mfa.getAuthenticatorAssuranceLevel()` and
`supabase.auth.mfa.listFactors()` APIs to identify the AAL level of the session
and any factors that are enabled for a user, similar to how you would use these
on the browser.
However, encountering a different AAL level on the server may not actually be a
security problem. Consider these likely scenarios:
1. User signed-in with a conventional method but closed their tab on the MFA
flow.
2. User forgot a tab open for a very long time. (This happens more often than
you might imagine.)
3. User has lost their authenticator device and is confused about the next
steps.
We thus recommend you redirect users to a page where they can authenticate
using their additional factor, instead of rendering a HTTP 401 Unauthorized or
HTTP 403 Forbidden content.
### APIs
If your application uses the Supabase Database, Storage or Edge Functions, just
using Row Level Security policies will give you sufficient protection. In the
event that you have other APIs that you wish to protect, follow these general
guidelines:
1. **Use a good JWT verification and parsing library for your language.**
This will let you securely parse JWTs and extract their claims.
2. **Retrieve the `aal` claim from the JWT and compare its value according to
your needs.**
If you've encountered an AAL level that can be increased, ask the user to
continue the login process instead of logging them out.
3. **Use the `https://<project-ref>.supabase.co/rest/v1/auth/factors` REST
endpoint to identify if the user has enrolled any MFA factors.**
Only `verified` factors should be acted upon.
## Frequently asked questions
### Why is there a challenge and verify API when challenge does not do much?
TOTP is not going to be the only MFA factor Supabase Auth is going to support
in the future. By separating out the challenge and verify steps, we're making
the library forward compatible with new factors we may add in the future --
such as SMS or WebAuthn. For example, for SMS the `challenge` endpoint would
actually send out the SMS with the authentication code.
### What's inside the QR code?
The TOTP QR code encodes a URI with the `otpauth` scheme. It was [initially
introduced by Google
Authenticator](https://github.com/google/google-authenticator/wiki/Key-Uri-Format)
but is now universally accepted by all authenticator apps.
### How do I check _when_ a user went through MFA?
Access tokens issued by Supabase Auth contain an `amr` (Authentication Methods
Reference) claim. It is an array of objects that indicate what authentication
methods the user has used so far.
For example, the following structure describes a user that first signed in with
a password-based method, and then went through TOTP MFA 2 minutes and 12
seconds later. The entries are ordered most recent method first!
```json
{
"amr": [
{
"method": "mfa/totp",
"timestamp": 1666086056
},
{
"method": "password",
"timestamp": 1666085924
}
]
}
```
Use the `supabase.auth.getAuthenticatorAssuranceLevel()` method to get easy
access to this information in your browser app.
You can use this PostgreSQL snippet in RLS policies, too:
```sql
json_query_path(auth.jwt(), '$.amr[0]')
```
- [`json_query_path(json,
path)`](https://www.postgresql.org/docs/current/functions-json.html#FUNCTIONS-JSON-PROCESSING-TABLE)
is a function that allows access to elements in a JSON object according to a
[SQL/JSON
path](https://www.postgresql.org/docs/current/functions-json.html#FUNCTIONS-SQLJSON-PATH).
- `$.amr[0]` is a SQL/JSON path expression that fetches the most recent
authentication method in the JWT.
Once you have extracted the most recent entry in the array, you can compare the
`method` and `timestamp` to enforce stricter rules.
Currently recognized methods are:
- `password` - any password based sign in.
- `otp` - any one-time password based sign in (email code, SMS code, magic
link).
- `oauth` - any OAuth based sign in (social login).
- `totp` - a TOTP additional factor.
This list will expand in the future.
@@ -1,97 +0,0 @@
---
id: auth-notion
title: 'Login with Notion'
description: Add Notion OAuth to your Supabase project
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
To enable Notion Auth for your project, you need to set up a Notion Application and add the Application OAuth credentials to your Supabase Dashboard.
## Overview
Setting up Notion logins for your application consists of 3 parts:
- Create and configure a Notion Application [Notion Developer Portal](https://www.notion.so/my-integrations)
- Retrieve your OAuth client ID and OAuth client secret and add them to your [Supabase Project](https://app.supabase.com)
- Add the login code to your [Supabase JS Client App](https://github.com/supabase/supabase-js)
## Create your notion integration
- Go to [developers.notion.com](https://developers.notion.com/).
- Click "View my integrations" and login.
![notion.so](/img/guides/auth-notion/notion.png)
- Once logged in, go to [notion.so/my-integrations](https://notion.so/my-integrations) and create a new integration.
- When creating your integration, ensure that you select "Public integration" under "Integration type" and "Read user information including email addresses" under "Capabilities".
- You will need to add a redirect uri, see [Add the redirect uri](#add-the-redirect-uri)
- Once you've filled in the necessary fields, click "Submit" to finish creating the integration.
![notion.so](/img/guides/auth-notion/notion-developer.png)
## Add the redirect URI
- After selecting "Public integration", you should see an option to add "Redirect URIs".
![notion.so](/img/guides/auth-notion/notion-redirect-uri.png)
You can retrieve the redirect uri with the following steps:
- Go to your [Supabase Project Dashboard](https://app.supabase.com).
- Click on the `Settings` icon at the bottom of the left sidebar.
- Click on `API` in the list.
- Under Config / URL you'll find your API URL, you can click `Copy` to copy it to the clipboard.
- Add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`.
Your redirect uri should look like the following: `https://<project-ref>.supabase.co/auth/v1/callback`
<video width="99%" muted playsInline controls="true">
<source
src="/docs/videos/api/api-url-and-key.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
## Add your Notion credentials into your Supabase Project
- Once you've created your notion integration, you should be able to retrieve the "OAuth client ID" and "OAuth client secret" from the "OAuth Domain and URIs" tab.
![notion.so](/img/guides/auth-notion/notion-creds.png)
- Go to your [Supabase Project Dashboard](https://app.supabase.com)
- In the left sidebar, click the `Authentication` icon (near the top)
- Click `Settings` from the list to go to the `Authentication Settings` page
- Under `External OAuth Providers` turn `Notion Enabled` to ON
- Enter the "OAuth client ID" and "OAuth client secret" obtained in the `client id` and `client secret` fields.
- Click `Save`
## Add login code to your client app
When your user signs in, call [signInWithOAuth()](/docs/reference/javascript/auth-signinwithoauth) with `notion` as the `provider`:
```js
async function signInWithNotion() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'notion',
})
}
```
When your user signs out, call [signOut()](/docs/reference/javascript/auth-signout) to remove them from the browser session and any objects from localStorage:
```js
async function signout() {
const { error } = await supabase.auth.signOut()
}
```
## Resources
- [Supabase Account - Free Tier OK](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Notion Account](https://notion.so)
- [Notion Developer Portal](https://www.notion.so/my-integrations)
@@ -1,106 +0,0 @@
---
id: auth-slack
title: 'Login with Slack'
description: Add Slack OAuth to your Supabase project
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
To enable Slack Auth for your project, you need to set up a Slack OAuth application and add the application credentials to your Supabase Dashboard.
## Overview
Setting up Slack logins for your application consists of 3 parts:
- Create and configure a Slack Project and App on the [Slack Developer Dashboard](https://api.slack.com/apps).
- Add your Slack `API Key` and `API Secret Key` to your [Supabase Project](https://app.supabase.com).
- Add the login code to your [Supabase JS Client App](https://github.com/supabase/supabase-js).
## Access your Slack Developer account
- Go to [api.slack.com](https://api.slack.com/apps).
- Click on `Your Apps` at the top right to log in.
![Slack Developer Portal.](/img/guides/auth-slack/slack-portal.png)
## Find your callback URL
The next step requires a callback URL, which looks like this:
`https://<project-ref>.supabase.co/auth/v1/callback`
- Go to your [Supabase Project Dashboard](https://app.supabase.com).
- Click on the `Settings` icon at the bottom of the left sidebar.
- Click on `API` in the list.
- Under Config / URL you'll find your API URL, you can click `Copy` to copy it to the clipboard.
- Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`.
<video width="99%" muted playsInline controls="true">
<source
src="/docs/videos/api/api-url-and-key.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
## Create a Slack OAuth app
- Go to [api.slack.com](https://api.slack.com/apps).
- Click on `Create an App`
Under `Create an app...`:
- Click `From scratch`
- Type the name of your app
- Select your `Slack Workspace`
- Click `Create App`
Under `App Credentials`:
- Copy and save your newly-generated `Client ID`
- Copy and save your newly-generated `Client Secret`
- Click `Permissions`
Under `Redirect URLs`:
- Click `Add New Redirect URL`
- Paste your `Callback URL` then click `Add`
- Click `Save URLs`
## Enter your Slack credentials into your Supabase Project
- Go to your [Supabase Project Dashboard](https://app.supabase.com).
- In the left sidebar, click the `Authentication` icon (near the top).
- Click `Settings` from the list to go to the `Authentication Settings` page.
- Enter the final (hosted) URL of your app under `Site URL` (this is important).
- Under `External OAuth Providers` turn `Slack Enabled` to ON.
- Enter your `Client ID` (`client_id`) and `Client Secret` (`client_secret`) saved in the previous step.
- Click `Save`.
## Add login code to your client app
When your user signs in, call [signInWithOAuth()](/docs/reference/javascript/auth-signinwithoauth) with `slack` as the `provider`:
```js
async function signInWithSlack() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'slack',
})
}
```
When your user signs out, call [signOut()](/docs/reference/javascript/auth-signout) to remove them from the browser session and any objects from localStorage:
```js
async function signout() {
const { error } = await supabase.auth.signOut()
}
```
## Resources
- [Supabase Account - Free Tier OK](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Slack Developer Dashboard](https://api.slack.com/apps)
@@ -1,101 +0,0 @@
---
id: auth-spotify
title: 'Login with Spotify'
description: Add Spotify OAuth to your Supabase project
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
To enable Spotify Auth for your project, you need to set up a Spotify OAuth application and add the application credentials to your Supabase Dashboard.
## Overview
Setting up Spotify logins for your application consists of 3 parts:
- Create and configure a Spotify Project and App on the [Spotify Developer Dashboard](https://developer.spotify.com/dashboard/).
- Add your Spotify `API Key` and `API Secret Key` to your [Supabase Project](https://app.supabase.com).
- Add the login code to your [Supabase JS Client App](https://github.com/supabase/supabase-js).
## Access your Spotify Developer account
- Log into [Spotify](https://spotify.com)
- Access the [Spotify Developer Dashboard](https://developer.spotify.com/dashboard)
![Spotify Developer Portal.](/img/guides/auth-spotify/spotify-portal.png)
## Find your callback URL
The next step requires a callback URL, which looks like this:
`https://<project-ref>.supabase.co/auth/v1/callback`
- Go to your [Supabase Project Dashboard](https://app.supabase.com).
- Click on the `Settings` icon at the bottom of the left sidebar.
- Click on `API` in the list.
- Under Config / URL you'll find your API URL, you can click `Copy` to copy it to the clipboard.
- Now just add `/auth/v1/callback` to the end of that to get your full `OAuth Redirect URI`.
<video width="99%" muted playsInline controls="true">
<source
src="/docs/videos/api/api-url-and-key.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
## Create a Spotify OAuth app
- Log into [Spotify](https://spotify.com).
- Go to the [Spotify Developer Dashboard](https://developer.spotify.com/dashboard)
- Click `Create an App`
- Type your `App name`
- Type your `App description`
- Check the box to agree with the `Developer TOS and Branding Guidelines`
- Click `Create`
- Save your `Client ID`
- Save your `Client Secret`
- Click `Edit Settings`
Under `Redirect URIs`:
- Paste your Supabase Callback URL in the box
- Click `Add`
- Click `Save` at the bottom
## Enter your Spotify credentials into your Supabase Project
- Go to your [Supabase Project Dashboard](https://app.supabase.com).
- In the left sidebar, click the `Authentication` icon (near the top).
- Click `Settings` from the list to go to the `Authentication Settings` page.
- Enter the final (hosted) URL of your app under `Site URL` (this is important).
- Under `External OAuth Providers` turn `Spotify Enabled` to ON.
- Enter your `Client ID` (`client_id`) and `Client Secret` (`client_secret`) saved in the previous step.
- Click `Save`.
## Add login code to your client app
When your user signs in, call [signInWithOAuth()](/docs/reference/javascript/auth-signinwithoauth) with `spotify` as the `provider`:
```js
async function signInWithSpotify() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'spotify',
})
}
```
When your user signs out, call [signOut()](/docs/reference/javascript/auth-signout) to remove them from the browser session and any objects from localStorage:
```js
async function signout() {
const { error } = await supabase.auth.signOut()
}
```
## Resources
- [Supabase Account - Free Tier OK](https://supabase.com)
- [Supabase JS Client](https://github.com/supabase/supabase-js)
- [Spotify Developer Dashboard](https://developer.spotify.com/dashboard/)
Loaded 100 of 786 files, more files were not shown because too many files have changed in this diff. Show more