openref: 0.1 info: id: reference/supabase-kotlin title: Supabase Kotlin Client description: | Supabase Kotlin. specUrl: https://github.com/supabase/supabase/edit/master/apps/docs/spec/supabase_kt_v1.yml slugPrefix: '/' libraries: - name: 'Kotlin' id: 'kt' version: '0.0.1' functions: - id: initializing title: 'Initializing' description: | ### Create Supabase Client Independently of which Supabase module you are using, you will need to initialize the main client first and install the module. To create a new client, you can use the `createSupabaseClient` function. When installing a module, you can pass a block to configure it. ### OAuth and OTP link verification [supabase-kt](https://github.com/supabase-community/supabase-kt) provides several platform implementations for OAuth and OTP link verification. \ **On JVM**, it uses a HTTP Callback Server to receive the session data from a successful OAuth sign-in. *Note: OTP link verification such as sign ups are not supported on JVM. You may have to send a verification token rather than a url in your E-Mail. To send the token, rather than a redirect url, you have to change `{{ .ConfirmationURL }}` in your sign up email to `{{ .Token }}`* **On Android, IOS & macOS**, it uses deeplinks. Refer to the guide below on how to setup deeplinks. Alternatively you could use Native Google Auth or a WebView for OAuth. Refer to our [demo](https://github.com/supabase-community/supabase-kt/tree/master/demos/android-login) to learn more. **On JS**, it uses the website origin as the callback url. Session importing gets handled automatically. **Windows, tvOS, watchOS & Linux** currently have no default implementation. Feel free to create a PR. You always make your own implementation and use `gotrue.parseSessionFromFragment(fragment)` or `gotrue.parseSessionFromUrl(url)` to let [supabase-kt](https://github.com/supabase-community/supabase-kt) handle the parsing after receiving a callback. Then you can simply use `gotrue.importSession(session)`. ### Configure deeplink callbacks for Authentication Deeplinks are supported on Android, IOS and macOS. 1. **Setup a deeplink for you app** \ On Android you may setup a [deeplink](https://developer.android.com/training/app-links/deep-linking) in your Android manifest. \ On IOS & macOS you may setup a [url scheme](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app). 2. **Add your deeplink to the [redirect URLs](https://supabase.com/dashboard/project/_/auth/url-configuration)** \ **Pattern**: scheme://host 3. **Configure the GoTrue plugin** You have to set the `host` and the `scheme` in the GoTrue config: ```kotlin install(GoTrue) { host = "deeplink host" // this can be anything, eg. your package name or app/company url (not your supabase url) scheme = "deeplink scheme" //Android only, you can also change that OAuth/SSO logins open in a custom tab, rather than an external browser: defaultExternalAuthAction = ExternalAuthAction.CUSTOM_TABS //defaults to EXTERNAL_BROWSER } ``` 4. **Call platform specific function on startup** \ On Android: `supabase.handleDeeplinks(intent)` \ On IOS/macOS: `supabase.handleDeeplinks(url)` Then you can just sign in using OAuth: ```kotlin supabase.gotrue.loginWith(Google) ``` Or open OTP links directly in your app. ### PKCE Authentication flow supabase-kt supports the [PKCE authentication flow](https://supabase.com/blog/supabase-auth-sso-pkce). To use it, you just have to change the `flowType` in the GoTrue configuration: ```kotlin install(GoTrue) { flowType = FlowType.PKCE } ``` That's it! If you already implemented deeplinks to handle OTPs and OAuth you don't have to change anything! examples: - id: initialize-client name: Initialize Client code: | ```kotlin val supabase = createSupabaseClient( supabaseUrl = "https://xyzcompany.supabase.co", supabaseKey = "publishable-or-anon-key" ) { install(GoTrue) install(Postgrest) //install other modules } ``` - id: configure-gotrue name: Configure GoTrue module code: | ```kotlin val supabase = createSupabaseClient( supabaseUrl = "https://xyzcompany.supabase.co", supabaseKey = "publishable-or-anon-key" ) { install(GoTrue) { alwaysAutoRefresh = false // default: true autoLoadFromStorage = false // default: true //and more... } } ``` description: | **Common:** `alwaysAutoRefresh` - whether the GoTrue plugin should always auto refresh expired sessions automatically. Default: `true` `autoLoadFromStorage` - whether the GoTrue plugin should automatically load the session from the session manager. Default: `true` `autoSaveToStorage` - whether the GoTrue plugin should automatically save the session to the session manager. Default: `true` `flowType` - Which authentication flow to use. Currently available: FlowType.PKCE and FlowType.IMPLICIT. Default: `FlowType.IMPLICIT` `codeVerifierCache` - Interface for saving and loading codes for the PKCE authentication flow. Default: `SettingsCodeVerifierCache` `customUrl` - Custom url for the GoTrue API. Can be safely ignored when using Supabase. Default: `null` `jwtToken` - Plugin specific JWT Token. Can be ignored when using the GoTrue plugin. Default: `null` `retryDelay` - Duration after which the GoTrue plugin should retry a failed session refresh. Default: `10.seconds` `sessionManager` - Interface for saving and loading the user session. Default: `SettingsSessionManager` **Android & IOS:** `scheme` - The scheme for the redirect url, when using deep linking. Default: `supabase` `host` - The host for the redirect url, when using deep linking. Default: `login` **Android:** `enableLifecycleCallbacks` - Whether to stop auto-refresh on focus loss, and resume it on focus again. Default: `true` **Desktop:** `httpPort`: The port the web server is running on, when signing in with OAuth. Default: `0` (random port). `timeout`: The timeout for the web server, when signing in with OAuth. Default: `1.minutes`. `htmlTitle`: The title of the redirect page, when signing in with OAuth. Default: `"Supabase Auth"`. `htmlText`: The text of the redirect page, when signing in with OAuth. Default: `"Logged in. You may continue in your app."`. `htmlIconUrl`: The icon of the redirect page, when signing in with OAuth. Default: `"https://supabase.com/brand-assets/supabase-logo-icon.png"`. - id: configure-postgrest name: Configure PostgREST module code: | ```kotlin val supabase = createSupabaseClient( supabaseUrl = "https://xyzcompany.supabase.co", supabaseKey = "publishable-or-anon-key" ) { install(Postgrest) { defaultSchema = "schema" // default: "public" propertyConversionMethod = PropertyConversionMethod.SERIAL_NAME // default: PropertyConversionMethod.CAMEL_CASE_TO_SNAKE_CASE } } ``` description: | `propertyConversionMethod` - The method to use to convert the property names to the column names when applying filters & using the update method. Default: `PropertyConversionMethod.CAMEL_CASE_TO_SNAKE_CASE` `defaultSchema` - The default schema to use for database requests. Default: `public` `customUrl` - Custom url for the PostgREST API. Can be safely ignored when using Supabase. Default: `null` `jwtToken` - Plugin specific JWT Token. Can be ignored when using the GoTrue plugin. Default: `null` - id: configure-storage name: Configure Storage module code: | ```kotlin val supabase = createSupabaseClient( supabaseUrl = "https://xyzcompany.supabase.co", supabaseKey = "publishable-or-anon-key" ) { install(Storage) { transferTimeout = 90.seconds // Default: 120 seconds } } ``` description: | `transferTimeout` - the timeout for uploading and downloading files. Default: `120.seconds` `resumable.cache` - Interface for storing resumable upload urls. Default: `SettingsResumableCache` `resumable.defaultChunkSize` - The default chunk size for resumable uploads. Supabase currently only supports a chunk size of 6MB, so be careful when changing this value. Default: `6MB` `resumable.retryTimeout` - the timeout for retrying resumable uploads when uploading a chunk fails. Default: `5.seconds` `resumable.onlyUpdateStateAfterChunk` - whether the upload state should only be updated after a chunk was uploaded successfully or also when the chunk is currently being uploaded. Default: `false` `customUrl` - Custom url for the Storage API. Can be safely ignored when using Supabase. Default: `null` `jwtToken` - Plugin specific JWT Token. Can be ignored when using the GoTrue plugin. Default: `null` - id: configure-realtime name: Configure Realtime module code: | ```kotlin val supabase = createSupabaseClient( supabaseUrl = "https://xyzcompany.supabase.co", supabaseKey = "publishable-or-anon-key" ) { install(Realtime) { reconnectDelay = 5.seconds // Default: 7 seconds } } ``` description: | `reconnectDelay` - The delay between reconnect attempts. Default: `7.seconds` `heartbeatInterval` - The interval between heartbeat messages. Default: `15.seconds` `disconnectOnSessionLoss` - Whether to disconnect from the websocket when the session is lost. Default: `true` `secure` - Whether to use wss or ws. Defaults to [SupabaseClient.useHTTPS] when null `websocketConfig` - Custom Ktor websocket config `customUrl` - Custom url for the Realtime websocket. Can be safely ignored when using Supabase. Default: `null` `jwtToken` - Plugin specific JWT Token. Can be ignored when using the GoTrue plugin. Default: `null` - id: configure-functions name: Configure Functions plugin code: | ```kotlin val supabase = createSupabaseClient( supabaseUrl = "https://xyzcompany.supabase.co", supabaseKey = "publishable-or-anon-key" ) { install(Functions) { //no custom settings } } ``` description: | `customUrl` - Custom url for the Functions API. Can be safely ignored when using Supabase. Default: `null` `jwtToken` - Plugin specific JWT Token. Can be ignored when using the GoTrue plugin. Default: `null` - id: configure-graphql name: Configure GraphQL plugin code: | ```kotlin val supabase = createSupabaseClient( supabaseUrl = "https://xyzcompany.supabase.co", supabaseKey = "publishable-or-anon-key" ) { install(GraphQL) { apolloConfiguration { //custom configuration } } } ``` description: | `apolloConfiguration` - Custom configuration for the ApolloClient `customUrl` - Custom url for the GraphQL API. Can be safely ignored when using Supabase. Default: `null` `jwtToken` - Plugin specific JWT Token. Can be ignored when using the GoTrue plugin. Default: `null` **You can access the created ApolloClient via `supabase.graphql.apolloClient`, which automatically adds the required headers depending on your session.** - id: select title: 'Fetch data: select()' notes: | Perform a SELECT query on the table or view. - When calling a `decode` method, you have to provide a [serializable class](/docs/reference/kotlin/installing#serialization) as the type parameter. - You can provide a `Columns` object to select specific columns. - You can provide a [filter](/docs/reference/kotlin/using-filters) block to filter the results examples: - id: getting-your-data name: Getting your data isSpotlight: true code: | ```kotlin val city = supabase.postgrest["cities"].select().decodeSingle() ``` - id: selecting-specific-columns name: Selecting specific columns description: You can select specific fields from your tables. code: | ```kotlin val city = supabase.postgrest["cities"].select(columns = Columns.list("id, name")).decodeSingle() ``` - id: query-foreign-tables name: Query foreign tables description: If your database has foreign key relationships, you can query related tables too. code: | ```kotlin val country = supabase.postgrest["countries"] .select( columns = Columns.raw( """ id, name, cities ( id, name ) """) ) .decodeSingle() ``` note: | What about join tables If you're in a situation where your tables are **NOT** directly related, but instead are joined by a _join table_, you can still use the `select()` method to query the related data. The PostgREST engine detects the relationship automatically. For more details, [follow the link](https://postgrest.org/en/latest/api.html#embedding-through-join-tables). - id: query-the-same-foreign-table-multiple-times name: Query the same foreign table multiple times description: | Sometimes you will need to query the same foreign table twice. In this case, you can use the name of the joined column to identify which join you intend to use. For convenience, you can also give an alias for each column. code: | ```kotlin val message = supabase.postgrest["messages"] .select(columns = Columns.raw( """ content, from: sender_id(name), to: receiver_id(name) """)) .decodeSingle() ``` - id: querying-with-count-option name: Querying with count option description: | You can get the number of rows by using the count option. Allowed values for count option are [Count.EXACT](https://postgrest.org/en/stable/api.html#exact-count), [Count.PLANNED](https://postgrest.org/en/stable/api.html#planned-count) and [Count.ESTIMATED](https://postgrest.org/en/stable/api.html#estimated-count). code: | ```kotlin val count = supabase.postgrest["countries"] .select(head = true, count = Count.EXACT) .count()!! ``` - id: querying-json-data name: Querying JSON data description: | If you have data inside of a JSONB column, you can apply select and query filters to the data values. Postgres offers a [number of operators](https://www.postgresql.org/docs/current/functions-json.html) for querying JSON data. Also see [PostgREST docs](http://postgrest.org/en/v7.0.0/api.html#json-columns) for more details. code: | ```kotlin val user = supabase.postgrest["users"] .select(columns = Columns.raw( """ id, name address->city """) .decodeSingle() ``` - id: insert title: 'Create data: insert()' $ref: '@supabase/postgrest-js."lib/PostgrestQueryBuilder".PostgrestQueryBuilder.insert' notes: | - When calling an `insert` method, you have to provide a [serializable value](/docs/reference/kotlin/installing#serialization). - By default, every time you run `insert()`, the client library will make a `select` to return the full record. This is convenient, but it can also cause problems if your policies are not configured to allow the `select` operation. If you are using Row Level Security and you are encountering problems, try setting the `returning` param to `Returning.MINIMAL`. examples: - id: create-a-record name: Create a record isSpotlight: true code: | ```kotlin val city = City(name = "The Shire", countryId = 554) supabase.postgrest["cities"].insert(city, returning = Returning.MINIMAL) //returning defaults to Returning.REPRESENTATION ``` - id: bulk-create name: Bulk create description: | When running a bulk create, the operation is handled in a single transaction. If any of the inserts fail, all other operations are rolled back. code: | ```kotlin val theShire = City(name = "The Shire", countryId = 554) val rohan = City(name = "Rohan", countryId = 554) supabase.postgrest["cities"].insert(listOf(theShire, rohan), returning = Returning.MINIMAL) //returning defaults to Returning.REPRESENTATION ``` - id: fetch-inserted-data name: Fetch inserted record code: | ```kotlin val theShire = City(name = "The Shire", countryId = 554) val rohan = City(name = "Rohan", countryId = 554) val result = supabase.postgrest["cities"].insert(listOf(theShire, rohan)).decodeList() ``` - id: update title: 'Modify data: update()' notes: | - `update()` should always be combined with a [filter](/docs/reference/kotlin/using-filters) block to avoid updating all records. - When calling `insert` or `update`, you have to provide a [serializable value](/docs/reference/kotlin/installing#serialization) in the function parameter. examples: - id: updating-your-data name: Updating your data isSpotlight: true code: | ```kotlin supabase.postgrest["characters"].update( { Character::name setTo "Han Solo" //or set("name", "Han Solo") } ) { Character::id eq 1 //or eq("id", 1) } ``` - id: update-a-record-and-return-it name: Update a record and return it code: | ```kotlin val newCharacter = supabase.postgrest["characters"].update( { Character::name setTo "Han Solo" //or set("name", "Han Solo") } ) { Character::id eq 1 //or eq("id", 1) }.decodeSingle() ``` data: sql: | ```sql create table characters (id int8 primary key, name text); insert into characters (id, name) values (1, 'Han'); ``` response: | ```json { "data": [ { "id": 1, "name": "Han Solo" } ], "status": 200, "statusText": "OK" } ``` hideCodeBlock: true - id: updating-json-data name: Updating JSON data description: | Postgres offers a [number of operators](https://www.postgresql.org/docs/current/functions-json.html) for working with JSON data. Right now it is only possible to update an entire JSON document, but we are [working on ideas](https://github.com/PostgREST/postgrest/issues/465) for updating individual keys. code: | ```kotlin val address = Address(street = "Melrose Place", postcode = 90210) supabase.postgrest["users"].update( { User::address setTo address } ) { User::id eq 1 //or eq("address->postcode", 90210) }.decodeSingle() ``` - id: upsert title: 'Upsert data: upsert()' $ref: '@supabase/postgrest-js."lib/PostgrestQueryBuilder".PostgrestQueryBuilder.upsert' notes: | - Primary keys should be included in the data payload in order for an update to work correctly. - Primary keys must be natural, not surrogate. There are however, [workarounds](https://github.com/PostgREST/postgrest/issues/1118) for surrogate primary keys. - If you need to insert new data and update existing data at the same time, use [Postgres triggers](https://github.com/supabase/postgrest-js/issues/173#issuecomment-825124550). - When calling `insert` or `update`, you have to provide a [serializable value](/docs/reference/kotlin/installing#serialization) in the function parameter. examples: - id: upsert-your-data name: Upsert your data isSpotlight: true code: | ```kotlin val toUpsert = Message(id = 3, message = "foo", username = "supabot") supabase.postgrest["messages"].insert(toUpsert, upsert = true) ``` - id: upserting-into-tables-with-constraints name: Upserting into tables with constraints description: | Running the following will cause Supabase to upsert data into the `users` table. If the username 'supabot' already exists, the `onConflict` argument tells Supabase to overwrite that row based on the column passed into `onConflict`. isSpotlight: true code: | ```kotlin let toUpsert = User(username = "supabot") supabase.postgrest["users"].insert(toUpsert, upsert = true, onConflict = "username") ``` - id: upsert-return-row-count name: Return the exact number of rows isSpotlight: true code: | ```kotlin let toUpsert = User(username = "supabot") val count = supabase.postgrest["users"].insert(toUpsert, upsert = true, onConflict = "username", count = Count.EXACT).count() ``` - id: delete title: 'Delete data: delete()' $ref: '@supabase/postgrest-js."lib/PostgrestQueryBuilder".PostgrestQueryBuilder.delete' notes: | - `delete()` should always be combined with a [filter](/docs/reference/kotlin/using-filters) block to target the item(s) you wish to delete. - If you use `delete()` with filters and you have [RLS](/docs/learn/auth-deep-dive/auth-row-level-security) enabled, only rows visible through `SELECT` policies are deleted. Note that by default no rows are visible, so you need at least one `SELECT`/`ALL` policy that makes the rows visible. examples: - id: delete-records name: Delete records isSpotlight: true code: | ```kotlin supabase.postgrest["cities"].delete { City::id eq 666 //or eq("id", 666) } ``` - id: fetch-delete-records name: Fetch deleted records code: | ```kotlin val deletedCity = supabase.postgrest["cities"].delete { City::id eq 666 //or eq("id", 666) }.decodeSingle() ``` - id: rpc title: 'Database Functions: rpc()' description: | You can call functions as a "Remote Procedure Call". That's a fancy way of saying that you can put some logic into your database then call it from anywhere. It's especially useful when the logic rarely changes - like password resets and updates. - When calling `rpc` with parameters, you have to provide a [serializable value](/docs/reference/kotlin/installing#serialization) in the function parameter. examples: - id: call-a-database-function name: Call a database function isSpotlight: true description: This is an example invoking a database function. code: | ```kotlin supabase.postgrest.rpc("hello_world") ``` - id: with-parameters name: With Parameters code: | ```kotlin val rpcParams = City(name = "The Shire") supabase.postgrest.rpc("echo_city", rpcParams) ``` - id: using-filters title: Using Filters description: | Filters allow you to only return rows that match certain conditions. Filters can be used on `select()`, `update()`, and `delete()` queries. You can use two different types for applying filters: ```kotlin eq("country_id", 1) ``` And using a class property: ```kotlin City::countryId eq 1 ``` As you can see on the property syntax: the name of the `countryId` gets converted to `country_id`. By default, this is done by converting camel case to snake case, but you can customize this by changing the `PropertyConversionMethod` in the Postgrest Config If a database function returns a table response, you can also apply filters. examples: - id: applying-filters name: Applying a filter block description: | Filters can be applied on any of these functions: `select()`, `update()`, `upsert()`, `delete()`, and `rpc()` code: | ```kotlin supabase.postgrest["cities"].select(columns = Columns.list("name", "country_id")) { City::name eq "The Shire" //or eq("name", "The Shire") } ``` - id: multiple-filters name: Multiple filters on one column description: | Filters can be applied on any of these functions: `select()`, `update()`, `upsert()`, `delete()`, and `rpc()` code: | ```kotlin supabase.postgrest["characters"].select(columns = Columns.list("name, book_id")) { and { //when both are true Character::age gt 10 Character::age lt 150 } or { //when either one of the filters are true Character::name eq "Harry" Character::name eq "Dumbledore" } } ``` - id: filter-by-value-within-json-column name: Filter by values within a JSON column description: | Filters can be built up one step at a time and then executed. For example: data: sql: | ```sql create table users ( id int8 primary key, name text, address jsonb ); insert into users (id, name, address) values (1, 'Michael', '{ "postcode": 90210 }'), (2, 'Jane', null); ``` response: | ```json { "data": [ { "id": 1, "name": "Michael", "address": { "postcode": 90210 } } ], "status": 200, "statusText": "OK" } ``` code: | ```kotlin supabase.postgrest["users"].select { eq("address->postcode", 90210) } ``` - id: filter-foreign-tables name: Filter Foreign Tables code: | ```kotlin supabase.postgrest["orchestral_sections"].select( columns = Columns.raw(""" name, instruments!inner ( name ) """) ) { eq("instruments.name", "flute") } ``` data: sql: | ```sql create table orchestral_sections (id int8 primary key, name text); create table instruments ( id int8 primary key, section_id int8 not null references orchestral_sections, name text ); insert into orchestral_sections (id, name) values (1, 'strings'), (2, 'woodwinds'); insert into instruments (id, section_id, name) values (1, 2, 'flute'), (2, 1, 'violin'); ``` response: | ```json { "data": [ { "name": "woodwinds", "characters": [ { "name": "flute" } ] } ], "status": 200, "statusText": "OK" } ``` - id: or title: or() description: | Finds all rows satisfying at least one of the filters. notes: | examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["countries"].select(columns = Columns.list("name")) { or { Country::id eq 2 Country::name eq "Mordor" //or eq("id", 2) eq("name", "Mordor") } } ``` - id: use-or-with-and name: Use `or` with `and` code: | ```kotlin supabase.postgrest["countries"].select(columns = Columns.list("name")) { or { Country::id gt 3 and { Country::id eq 1 Country::name eq "Mordor" } } } ``` - id: not title: filterNot() description: | Finds all rows that don't satisfy the filter. notes: | - `.filterNot()` expects you to use the raw [PostgREST syntax](https://postgrest.org/en/stable/api.html#horizontal-filtering-rows) for the filter names and values. examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["countries"].select { filterNot("name", FilterOperation.IS, "") } ``` - id: eq title: eq() description: | Finds all rows whose value on the stated `column` exactly matches the specified `value`. examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["cities"].select(columns = Columns.list("name", "country_id")) { City::name eq "The Shire" //or eq("name", "The Shire") } ``` - id: with-update name: With `update()` code: | ```kotlin val toUpdate = City(name = "Mordor") supabase.postgrest["cities"].update(toUpdate) { City::name eq "The Shire" //or eq("name", "The Shire") } ``` - id: with-delete name: With `delete()` code: | ```kotlin supabase.postgrest["cities"].delete { City::name eq "Mordor" //or eq("name", "Mordor") } ``` - id: with-rpc name: With `rpc()` code: | ```kotlin supabase.postgrest.rpc("function") { City::name eq "Mordor" //or eq("name", "Mordor") } ``` - id: neq title: neq() description: | Finds all rows whose value on the stated `column` doesn't match the specified `value`. examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["cities"].select(columns = Columns.list("name", "country_id")) { City::name neq "The Shire" //or neq("name", "The Shire") } ``` - id: with-update name: With `update()` code: | ```kotlin val toUpdate = City(name = "Mordor") supabase.postgrest["cities"].update(toUpdate) { City::name neq "The Shire" //or neq("name", "The Shire") } ``` - id: with-delete name: With `delete()` code: | ```kotlin supabase.postgrest["cities"].delete { City::name neq "The Shire" //or neq("name", "The Shire") } ``` - id: with-rpc name: With `rpc()` code: | ```kotlin supabase.rpc("echo_all_cities") { neq("address->postcode", 90210) } ``` - id: gt title: gt() description: | Finds all rows whose value on the stated `column` is greater than the specified `value`. examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["cities"].select(columns = Columns.list("name")) { City::countryId gt 300 //or gt("country_id", 300) } ``` - id: with-update name: With `update()` code: | ```kotlin val toUpdate = City(name = "Mordor") supabase.postgrest["cities"].update(toUpdate) { City::countryId gt 300 //or gt("country_id", 300) } ``` - id: with-delete name: With `delete()` code: | ```kotlin supabase.postgrest["cities"].delete { City::countryId gt 300 //or gt("country_id", 300) } ``` - id: with-rpc name: With `rpc()` code: | ```kotlin supabase.postgrest.rpc("echo_all_cities") { City::countryId gt 250 //or gt("country_id", 300) } ``` - id: gte title: gte() description: | Finds all rows whose value on the stated `column` is greater than or equal to the specified `value`. examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["cities"].select(columns = Columns.list("name")) { City::countryId gte 300 //or gte("country_id", 300) } ``` - id: with-update name: With `update()` code: | ```kotlin val toUpdate = City(name = "Mordor") supabase.postgrest["cities"].update(toUpdate) { City::countryId gte 300 //or gte("country_id", 300) } ``` - id: with-delete name: With `delete()` code: | ```kotlin supabase.postgrest["cities"].delete { City::countryId gte 300 //or gte("country_id", 300) } ``` - id: with-rpc name: With `rpc()` code: | ```kotlin supabase.postgrest.rpc("echo_all_cities") { City::countryId gte 250 //or gte("country_id", 300) } ``` - id: lt title: lt() description: | Finds all rows whose value on the stated `column` is less than the specified `value`. examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["cities"].select(columns = Columns.list("name")) { City::countryId lt 300 //or lt("country_id", 300) } ``` - id: with-update name: With `update()` code: | ```kotlin val toUpdate = City(name = "Mordor") supabase.postgrest["cities"].update(toUpdate) { City::countryId lt 300 //or lt("country_id", 300) } ``` - id: with-delete name: With `delete()` code: | ```kotlin supabase.postgrest["cities"].delete { City::countryId lt 300 //or lt("country_id", 300) } ``` - id: with-rpc name: With `rpc()` code: | ```kotlin supabase.postgrest.rpc("echo_all_cities") { City::countryId lt 250 //or lt("country_id", 300) } ``` - id: lte title: lte() description: | Finds all rows whose value on the stated `column` is less than or equal to the specified `value`. examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["cities"].select(columns = Columns.list("name")) { City::countryId lte 300 //or lte("country_id", 300) } ``` - id: with-update name: With `update()` code: | ```kotlin val toUpdate = City(name = "Mordor") supabase.postgrest["cities"].update(toUpdate) { City::countryId lte 300 //or lte("country_id", 300) } ``` - id: with-delete name: With `delete()` code: | ```kotlin supabase.postgrest["cities"].delete { City::countryId lte 300 //or lte("country_id", 300) } ``` - id: with-rpc name: With `rpc()` code: | ```kotlin supabase.postgrest.rpc("echo_all_cities") { City::countryId lte 250 //or lte("country_id", 300) } ``` - id: like title: like() description: | Finds all rows whose value in the stated `column` matches the supplied `pattern` (case sensitive). examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["cities"].select(columns = Columns.list("name")) { City::name like "%la%" //or like("name", "%la%") } ``` - id: with-update name: With `update()` code: | ```kotlin val toUpdate = City(name = "Mordor") supabase.postgrest["cities"].update(toUpdate) { City::name like "%la%" //or like("name", "%la%") } ``` - id: with-delete name: With `delete()` code: | ```kotlin supabase.postgrest["cities"].delete { City::name like "%la%" //or like("name", "%la%") } ``` - id: with-rpc name: With `rpc()` code: | ```kotlin supabase.postgrest.rpc("echo_all_cities") { City::name like "%la%" //or like("name", "%la%") } ``` - id: ilike title: ilike() description: | Finds all rows whose value in the stated `column` matches the supplied `pattern` (case insensitive). examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["cities"].select(columns = Columns.list("name")) { City::name ilike "%la%" //or ilike("name", "%la%") } ``` - id: with-update name: With `update()` code: | ```kotlin val toUpdate = City(name = "Mordor") supabase.postgrest["cities"].update(toUpdate) { City::name ilike "%la%" //or ilike("name", "%la%") } ``` - id: with-delete name: With `delete()` code: | ```kotlin supabase.postgrest["cities"].delete { City::name ilike "%la%" //or ilike("name", "%la%") } ``` - id: with-rpc name: With `rpc()` code: | ```kotlin supabase.postgrest.rpc("echo_all_cities") { City::name ilike "%la%" //or ilike("name", "%la%") } ``` - id: is title: is_() description: | A check for exact equality (null, true, false), finds all rows whose value on the stated `column` exactly match the specified `value`. `is_` and `in_` filter methods are suffixed with `_` to avoid collisions with reserved keywords. examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["cities"].select(columns = Columns.list("name")) { City::name isExact null //or exact("name", null) } ``` - id: with-update name: With `update()` code: | ```kotlin val toUpdate = City(name = "Mordor") supabase.postgrest["cities"].update(toUpdate) { City::name isExact null //or exact("name", null) } ``` - id: with-delete name: With `delete()` code: | ```kotlin supabase.postgrest["cities"].delete { City::name isExact null //or exact("name", null) } ``` - id: with-rpc name: With `rpc()` code: | ```kotlin supabase.postgrest.rpc("echo_all_cities") { City::name isExact null //or exact("name", null) } ``` - id: in title: in_() description: | Finds all rows whose value on the stated `column` is found on the specified `values`. examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["cities"].select(columns = Columns.list("name")) { City::name isIn listOf("The Shire", "Mordor") //or isIn("name", listOf("The Shire", "Mordor")) } ``` - id: with-update name: With `update()` code: | ```kotlin val toUpdate = City(name = "Mordor") supabase.postgrest["cities"].update(toUpdate) { City::name isIn listOf("Hobbiton", "Edoras") //or isIn("name", listOf("Hobbiton", "Edoras")) } ``` - id: with-delete name: With `delete()` code: | ```kotlin supabase.postgrest["cities"].delete { City::name isIn listOf("Hobbiton", "Edoras") //or isIn("name", listOf("Hobbiton", "Edoras")) } ``` - id: with-rpc name: With `rpc()` code: | ```kotlin supabase.postgrest.rpc("echo_all_cities") { City::name isIn listOf("Hobbiton", "Edoras") //or isIn("name", listOf("Hobbiton", "Edoras")) } ``` - id: contains title: contains() examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["cities"].select(columns = Columns.list("name")) { City::mainExports contains listOf("oil") //or contains("main_exports", listOf("oil")) } ``` - id: with-update name: With `update()` code: | ```kotlin val toUpdate = City(name = "Mordor") supabase.postgrest["cities"].update(toUpdate) { City::mainExports contains listOf("oil") //or contains("main_exports", listOf("oil")) } ``` - id: with-delete name: With `delete()` code: | ```kotlin supabase.postgrest["cities"].delete { City::mainExports contains listOf("oil") //or contains("main_exports", listOf("oil")) } ``` - id: with-rpc name: With `rpc()` code: | ```kotlin supabase.postgrest.rpc("echo_all_cities") { City::mainExports contains listOf("oil") //or contains("main_exports", listOf("oil")) } ``` - id: range-lt title: rangeLt() description: | Only relevant for range columns. Match only rows where every element in column is less than any element in range. examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["reservations"].select { Reservation::during rangeLt ("2000-01-02 08:30" to "2000-01-02 09:30") //or rangeLt("during", "2000-01-02 08:30" to "2000-01-02 09:30") } ``` data: sql: | ```sql create table reservations ( id int8 primary key, room_name text, during tsrange ); insert into reservations (id, room_name, during) values (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'), (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)'); ``` response: | ```json { "data": [ { "id": 1, "room_name": "Emerald", "during": "[\"2000-01-01 13:00:00\",\"2000-01-01 15:00:00\")" } ], "status": 200, "statusText": "OK" } ``` description: | Postgres supports a number of [range types](https://www.postgresql.org/docs/current/rangetypes.html). You can filter on range columns using the string representation of range values. hideCodeBlock: true - id: range-gt title: rangeGt() description: | Only relevant for range columns. Match only rows where every element in column is greater than any element in range. examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["reservations"].select { Reservation::during rangeGt ("2000-01-02 08:30" to "2000-01-02 09:30") //or rangeGt("during", "2000-01-02 08:30" to "2000-01-02 09:30") } ``` data: sql: | ```sql create table reservations ( id int8 primary key, room_name text, during tsrange ); insert into reservations (id, room_name, during) values (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'), (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)'); ``` response: | ```json { "data": [ { "id": 2, "room_name": "Topaz", "during": "[\"2000-01-02 09:00:00\",\"2000-01-02 10:00:00\")" } ], "status": 200, "statusText": "OK" } ``` description: | Postgres supports a number of [range types](https://www.postgresql.org/docs/current/rangetypes.html). You can filter on range columns using the string representation of range values. hideCodeBlock: true - id: range-gte title: rangeGte() description: | Only relevant for range columns. Match only rows where every element in column is either contained in range or greater than any element in range. examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["reservations"].select { Reservation::during rangeGte ("2000-01-02 08:30" to "2000-01-02 09:30") //or rangeGte("during", "2000-01-02 08:30" to "2000-01-02 09:30") } ``` data: sql: | ```sql create table reservations ( id int8 primary key, room_name text, during tsrange ); insert into reservations (id, room_name, during) values (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'), (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)'); ``` response: | ```json { "data": [ { "id": 2, "room_name": "Topaz", "during": "[\"2000-01-02 09:00:00\",\"2000-01-02 10:00:00\")" } ], "status": 200, "statusText": "OK" } ``` description: | Postgres supports a number of [range types](https://www.postgresql.org/docs/current/rangetypes.html). You can filter on range columns using the string representation of range values. hideCodeBlock: true - id: range-lte title: rangeLte() description: | Only relevant for range columns. Match only rows where every element in column is either contained in range or less than any element in range. $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.rangeLte' examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["reservations"].select { Reservation::during rangeLte ("2000-01-02 08:30" to "2000-01-02 09:30") //or rangeLte("during", "2000-01-02 08:30" to "2000-01-02 09:30") } ``` data: sql: | ```sql create table reservations ( id int8 primary key, room_name text, during tsrange ); insert into reservations (id, room_name, during) values (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'), (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)'); ``` response: | ```json { "data": [ { "id": 1, "room_name": "Emerald", "during": "[\"2000-01-01 13:00:00\",\"2000-01-01 15:00:00\")" } ], "status": 200, "statusText": "OK" } ``` description: | Postgres supports a number of [range types](https://www.postgresql.org/docs/current/rangetypes.html). You can filter on range columns using the string representation of range values. hideCodeBlock: true - id: range-adjacent title: rangeAdjacent() description: | Only relevant for range columns. Match only rows where column is mutually exclusive to range and there can be no element between the two ranges. examples: - id: with-select name: With `select()` isSpotlight: true code: | ```kotlin supabase.postgrest["reservations"].select { Reservation::during adjacent ("2000-01-02 08:30" to "2000-01-02 09:30") //or adjacent("during", "2000-01-02 08:30" to "2000-01-02 09:30") } ``` data: sql: | ```sql create table reservations ( id int8 primary key, room_name text, during tsrange ); insert into reservations (id, room_name, during) values (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'), (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)'); ``` response: | ```json { "data": [ { "id": 1, "room_name": "Emerald", "during": "[\"2000-01-01 13:00:00\",\"2000-01-01 15:00:00\")" } ], "status": 200, "statusText": "OK" } ``` hideCodeBlock: true - id: overlaps title: overlaps() $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.overlaps' description: | Only relevant for array and range columns. Match only rows where column and value have an element in common. examples: - id: on-array-columns name: On array columns code: | ```kotlin supabase.postgrest["issues"].select(columns = Columns.list("title")) { Issue::tags overlaps listOf("is:closed", "severity:high") //or overlaps("tags", listOf("is:closed", "severity:high")) } ``` data: sql: | ```sql create table issues ( id int8 primary key, title text, tags text[] ); insert into issues (id, title, tags) values (1, 'Cache invalidation is not working', array['is:open', 'severity:high', 'priority:low']), (2, 'Use better names', array['is:open', 'severity:low', 'priority:medium']); ``` response: | ```json { "data": [ { "title": "Cache invalidation is not working" } ], "status": 200, "statusText": "OK" } ``` hideCodeBlock: true isSpotlight: true - id: on-range-columns name: On range columns code: | ```kotlin supabase.postgrest["issues"].select(columns = Columns.list("title")) { Issue::tags overlaps listOf("is:closed", "severity:high") //or overlaps("tags", listOf("is:closed", "severity:high")) } ``` data: sql: | ```sql create table reservations ( id int8 primary key, room_name text, during tsrange ); insert into reservations (id, room_name, during) values (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'), (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)'); ``` response: | ```json { "data": [ { "id": 1, "room_name": "Emerald", "during": "[\"2000-01-01 13:00:00\",\"2000-01-01 15:00:00\")" } ], "status": 200, "statusText": "OK" } ``` description: | Postgres supports a number of [range types](https://www.postgresql.org/docs/current/rangetypes.html). You can filter on range columns using the string representation of range values. hideCodeBlock: true - id: text-search title: textSearch() description: | Only relevant for text and tsvector columns. Match only rows where `column` matches the query string in `query`. For more information, see [Postgres full text search](https://supabase.com/docs/guides/database/full-text-search). examples: - id: text-search name: Text search code: | ```kotlin supabase.postgrest["quotes"].select(columns = Columns.list("catchphrase")) { textSearch(column = "catchphrase", query = "'fat' & 'cat'", config = "english", type = TextSearchType.YOUR_TYPE) } ``` - id: basic-normalization name: Basic normalization description: Uses PostgreSQL's `plainto_tsquery` function. code: | ```kotlin supabase.postgrest["quotes"].select(columns = Columns.list("catchphrase")) { textSearch(column = "catchphrase", query = "'fat' & 'cat'", config = "english", type = TextSearchType.PLAINTO) } ``` - id: full-normalization name: Full normalization description: Uses PostgreSQL's `phraseto_tsquery` function. code: | ```kotlin supabase.postgrest["quotes"].select(columns = Columns.list("catchphrase")) { textSearch(column = "catchphrase", query = "'fat' & 'cat'", config = "english", type = TextSearchType.PHRASETO) } ``` - id: web-search name: Websearch description: | Uses PostgreSQL's `websearch_to_tsquery` function. This function will never raise syntax errors, which makes it possible to use raw user-supplied input for search, and can be used with advanced operators. - `unquoted text`: text not inside quote marks will be converted to terms separated by & operators, as if processed by plainto_tsquery. - `"quoted text"`: text inside quote marks will be converted to terms separated by `<->` operators, as if processed by phraseto_tsquery. - `OR`: the word “or” will be converted to the | operator. - `-`: a dash will be converted to the ! operator. code: | ```kotlin supabase.postgrest["quotes"].select(columns = Columns.list("catchphrase")) { textSearch(column = "catchphrase", query = "'fat' & 'cat'", config = "english", type = TextSearchType.WEBSEARCH) } ``` - id: filter title: filter() $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.filter' notes: | filter() expects you to use the raw PostgREST syntax for the filter values. examples: - id: with-select name: With `select()` code: | ```kotlin supabase.postgrest["characters"].select { filter(column = "name", operator = FilterOperator.IN, value = "('Han', 'Katniss')") } ``` data: sql: | ```sql create table characters (id int8 primary key, name text); insert into characters (id, name) values (1, 'Luke'), (2, 'Leia'), (3, 'Han'); ``` response: | ```json { "data": [ { "id": 3, "name": "Han" } ], "status": 200, "statusText": "OK" } ``` hideCodeBlock: true isSpotlight: true - id: on-a-foreign-table name: On a foreign table code: | ```kotlin supabase.postgrest["orchestral_sections"].select( columns = Columns.raw(""" name, instruments!inner ( name ) """) ) { filter(column = "instruments.name", operator = FilterOperator.EQ, value = "flute") } ``` data: sql: | ```sql create table orchestral_sections (id int8 primary key, name text); create table instruments ( id int8 primary key, section_id int8 not null references orchestral_sections, name text ); insert into orchestral_sections (id, name) values (1, 'strings'), (2, 'woodwinds'); insert into instruments (id, section_id, name) values (1, 2, 'flute'), (2, 1, 'violin'); ``` response: | ```json { "data": [ { "name": "woodwinds", "instruments": [ { "name": "flute" } ] } ], "status": 200, "statusText": "OK" } ``` hideCodeBlock: true - id: order title: order() description: | Order the query result by column. $ref: '@supabase/postgrest-js.PostgrestTransformBuilder.order' examples: - id: with-select name: With `select()` code: | ```kotlin supabase.postgrest["characters"].select(columns = Columns.list("id", "name")) { order(column = "id", order = Order.DESCENDING) } ``` data: sql: | ```sql create table characters (id int8 primary key, name text); insert into characters (id, name) values (1, 'Luke'), (2, 'Leia'), (3, 'Han'); ``` response: | ```json { "data": [ { "id": 3, "name": "Han" }, { "id": 2, "name": "Leia" }, { "id": 1, "name": "Luke" } ], "status": 200, "statusText": "OK" } ``` hideCodeBlock: true isSpotlight: true - id: on-a-foreign-table name: On a foreign table code: | ```kotlin supabase.postgrest["orchestral_sections"].select( columns = Columns.raw( """ name, instruments ( name ) """ ) ) { order(column = "name", order = Order.DESCENDING, foreignTable = "instruments") } ``` data: sql: | ```sql create table orchestral_sections (id int8 primary key, name text); create table instruments ( id int8 primary key, section_id int8 not null references orchestral_sections, name text ); insert into orchestral_sections (id, name) values (1, 'strings'), (2, 'woodwinds'); insert into instruments (id, section_id, name) values (1, 1, 'harp'), (2, 1, 'violin'); ``` response: | ```json { "data": [ { "name": "strings", "instruments": [ { "name": "violin" }, { "name": "harp" } ] }, { "name": "woodwinds", "instruments": [] } ], "status": 200, "statusText": "OK" } ``` description: | Ordering on foreign tables doesn't affect the ordering of the parent table. hideCodeBlock: true - id: limit title: limit() description: | Limit the query result by count. $ref: '@supabase/postgrest-js.PostgrestTransformBuilder.limit' examples: - id: with-select name: With `select()` code: | ```kotlin supabase.postgrest["characters"].select { limit(count = 1) } ``` data: sql: | ```sql create table characters (id int8 primary key, name text); insert into characters (id, name) values (1, 'Luke'), (2, 'Leia'), (3, 'Han'); ``` response: | ```json { "data": [ { "name": "Luke" } ], "status": 200, "statusText": "OK" } ``` hideCodeBlock: true isSpotlight: true - id: on-a-foreign-table name: On a foreign table code: | ```kotlin supabase.postgrest["orchestral_sections"].select( columns = Columns.raw( """ name, instruments ( name ) """ ) ) { limit(count = 1, foreignTable = "instruments") } ``` data: sql: | ```sql create table orchestral_sections (id int8 primary key, name text); create table instruments ( id int8 primary key, section_id int8 not null references orchestral_sections, name text ); insert into orchestral_sections (id, name) values (1, 'strings'); insert into instruments (id, section_id, name) values (1, 1, 'harp'), (2, 1, 'violin'); ``` response: | ```json { "data": [ { "name": "strings", "cities": [ { "name": "harp" } ] } ], "status": 200, "statusText": "OK" } ``` hideCodeBlock: true - id: range title: range() description: | Limit the query result by from and to inclusively. examples: - id: with-select name: With `select()` code: | ```kotlin supabase.postgrest["characters"].select { range(1L..5L) } ``` data: sql: | ```sql create table characters (id int8 primary key, name text); insert into characters (id, name) values (1, 'Luke'), (2, 'Leia'), (3, 'Han'); ``` response: | ```json { "data": [ { "name": "Luke" }, { "name": "Leia" } ], "status": 200, "statusText": "OK" } ``` hideCodeBlock: true isSpotlight: true - id: auth-api title: 'Overview' notes: | - The auth methods can be accessed via the Supabase GoTrue Auth client. examples: - id: create-auth-client name: Create gotrue client isSpotlight: true code: | ```kotlin val supabase = createSupabaseClient(supabaseURL = "https://xyzcompany.supabase.co'", supabaseKey = "publishable-or-anon-key") { ... } val gotrue = supabase.gotrue ``` - id: sign-up title: 'signUp()' $ref: '@supabase/gotrue-js.GoTrueClient.signUp' notes: | Creates a new user. - By default, the user needs to verify their email address before signing in. To turn this off, disable **Confirm email** in [your project](https://supabase.com/dashboard/project/_/auth/providers). - **Confirm email** determines if users need to confirm their email address after signing up. - If **Confirm email** is enabled, the return value is the user and you won't be signed in automatically. - If **Confirm email** is disabled, the return value is null and you will be signed in instead. - When the user confirms their email address, they are redirected to the [`SITE_URL`](https://supabase.com/docs/guides/auth/redirect-urls) by default. You can modify your `SITE_URL` or add additional redirect URLs in [your project](https://supabase.com/dashboard/project/_/auth/url-configuration). - To learn how to handle OTP links & OAuth refer to [initializing](/docs/reference/kotlin/initializing) - If signUpWith() is called for an existing confirmed user: - If **Confirm email** is enabled in [your project](https://supabase.com/dashboard/project/_/auth/providers), an obfuscated/fake user object is returned. - If **Confirm email** is disabled, the error message, `User already registered` is returned. examples: - id: sign-up-email name: Sign up with email isSpotlight: true code: | ```kotlin val user = supabase.gotrue.signUpWith(Email) { email = "example@email.com" password = "example-password" } ``` - id: sign-up-phone name: Sign up with a phone number isSpotlight: true code: | ```kotlin val user = supabase.gotrue.signUpWith(Phone) { phoneNumber = "+4912345679" password = "example-password" } ``` - id: sign-up-with-additional-user-metadata name: Sign up with additional user metadata isSpotlight: false code: | ```kotlin val user = supabase.gotrue.signUpWith(Email) { email = "example@email.com" password = "example-password" data = buildJsonObject { put("first_name", "John") put("age", 24) } } ``` - id: sign-up-with-redirect name: Sign up with a redirect URL description: | - See [redirect URLs and wildcards](/docs/guides/auth/redirect-urls#use-wildcards-in-redirect-urls) to add additional redirect URLs to your project. code: | ```kotlin val user = supabase.gotrue.signUpWith(Email, redirectUrl = "https://example.com") { email = "example@email.com" password = "example-password" } ``` - id: sign-in-with-password title: 'loginWith()' $ref: '@supabase/gotrue-js.GoTrueClient.signInWithPassword' notes: | Logs in an existing user. - Requires either an email and password or a phone number and password. examples: - id: sign-in-with-email-and-password name: Sign in with email and password isSpotlight: true code: | ```kotlin supabase.gotrue.loginWith(Email) { email = "example@email.com" password = "example-password" } ``` - id: sign-in-with-phone-and-password name: Sign in with phone and password isSpotlight: false code: | ```kotlin supabase.gotrue.loginWith(Phone) { phoneNumber = "+4912345679" password = "example-password" } ``` - id: sign-in-with-id-token name: Sign in with id token isSpotlight: false code: | ```kotlin supabase.gotrue.loginWith(IDToken) { idToken = "token" provider = Google //Also supported: Apple, Azure and Facebook //optional: nonce = "nonce" data = buildJsonObject { //... } } ``` - id: sign-in-with-otp title: 'sendOtpTo()' $ref: '@supabase/gotrue-js.GoTrueClient.signInWithOtp' notes: | Sends a OTP to the user's email or phone number. - Requires either an email or phone number. - This method is used for passwordless sign-ins where a OTP is sent to the user's email or phone number. - If the user doesn't exist, `sendOtpTo()` will signup the user instead. To restrict this behavior, you can set `createUser` to `false`. - If you're using an email, you can configure whether you want the user to receive a magiclink or a OTP. - If you're using phone, you can configure whether you want the user to receive a OTP. - The magic link's destination URL is determined by the [`SITE_URL`](/docs/guides/auth/redirect-urls). - See [redirect URLs and wildcards](/docs/guides/auth/redirect-urls#use-wildcards-in-redirect-urls) to add additional redirect URLs to your project. - To learn how to handle OTP links & OAuth refer to [initializing](/docs/reference/kotlin/initializing) - Magic links and OTPs share the same implementation. To send users a one-time code instead of a magic link, [modify the magic link email template](https://supabase.com/dashboard/project/_/auth/templates) to include `{{ .Token }}` instead of `{{ .ConfirmationURL }}`. examples: - id: sign-in-with-email name: Sign in with email isSpotlight: true description: The user will be sent an email which contains either a magiclink or a OTP or both. By default, a given user can only request a OTP once every 60 seconds. code: | ```kotlin supabase.gotrue.sendOtpTo(Email) { email = "example@email.com" } ``` - id: sign-in-with-sms-otp name: Sign in with SMS OTP isSpotlight: false description: The user will be sent a SMS which contains a OTP. By default, a given user can only request a OTP once every 60 seconds. code: | ```kotlin supabase.gotrue.sendOtpTo(Phone) { phoneNumber = "+4912345679" } ``` - id: sign-in-with-oauth title: 'loginWith(OAuthProvider)' $ref: '@supabase/gotrue-js.GoTrueClient.signInWithOAuth' notes: | - This method is used for signing in using a third-party provider. - Supabase supports many different [third-party providers](https://supabase.com/docs/guides/auth#providers). - To learn how to handle OTP links & OAuth refer to [initializing](/docs/reference/kotlin/initializing) examples: - id: sign-in-using-a-third-party-provider name: Sign in using a third-party provider isSpotlight: true code: | ```kotlin supabase.gotrue.loginWith(Github) ``` - id: sign-in-using-a-third-party-provider with scopes name: Sign in using a third-party provider with scopes isSpotlight: true code: | ```kotlin supabase.gotrue.loginWith(Github) { scopes.add("email") } ``` - id: sign-in-using-a-third-party-provider-with-redirect name: Create a custom url isSpotlight: false description: | - When the third-party provider successfully authenticates the user, the provider redirects the user to the URL specified in the `redirectUrl` parameter. This parameter defaults to the [`SITE_URL`](/docs/guides/auth/redirect-urls). It does not redirect the user immediately after invoking this method. - See [redirect URLs and wildcards](/docs/guides/auth/redirect-urls#use-wildcards-in-redirect-urls) to add additional redirect URLs to your project. - oAuthUrl() provides the URL which needs to be opened in a browser. - The redirectTo URL needs to be setup correctly in your project under Authentication -> URL Configuration -> Redirect URLs. - To see how you can use a custom in-app browser on Android, check our [demo](https://github.com/supabase-community/supabase-kt/tree/development/demos/android-login) on GitHub. code: | ```kotlin val url = supabase.gotrue.oAuthUrl(Github, redirectUrl = "https://example.com") ``` - id: sign-in-with-scopes name: Create a custom url with scopes isSpotlight: false description: | If you need additional data from an OAuth provider, you can include a space-separated list of scopes in your request to get back an OAuth provider token. You may also need to specify the scopes in the provider's OAuth app settings, depending on the provider. The list of scopes will be documented by the third-party provider you are using and specifying scopes will enable you to use the OAuth provider token to call additional APIs supported by the third-party provider to get more information. code: | ```kotlin val url = supabase.gotrue.oAuthUrl(Github, redirectUrl = "https://example.com") { scopes.add("email") } ``` - id: sign-in-with-sso title: 'signInWithSSO()' $ref: '@supabase/gotrue-js.GoTrueClient.signInWithSSO' notes: | - Before you can call this method you need to [establish a connection](/docs/guides/auth/enterprise-sso/auth-sso-saml#managing-saml-20-connections) to an identity provider. Use the [CLI commands](/docs/reference/cli/supabase-sso) to do this. - If you've associated an email domain to the identity provider, you can use the `SSO.withDomain()` function in the `loginWith` method to start a sign-in flow. - In case you need to use a different way to start the authentication flow with an identity provider, you can use the `SSO.withProviderId` function. For example: - Mapping specific user email addresses with an identity provider. - Using different hints to identity the identity provider to be used by the user, like a company-specific page, IP address or other tracking information. - To learn how to handle OTP links & OAuth refer to [initializing](/docs/reference/kotlin/initializing) examples: - id: sign-in-with-domain name: Sign in with email domain isSpotlight: true code: | ```kotlin // You can extract the user's email domain and use it to trigger the // authentication flow with the correct identity provider. supabase.gotrue.loginWith(SSO.withDomain("company.com")) //the url was opened automatically, if you don't want that, provide a custom redirect url ``` - id: sign-in-with-provider-uuid name: Sign in with provider UUID isSpotlight: true code: | ```kotlin // Useful when you need to map a user's sign in request according // to different rules that can't use email domains. supabase.gotrue.loginWith(SSO.withProvider("21648a9d-8d5a-4555-a9d1-d6375dc14e92")) //the url was opened automatically, if you don't want that, provide a custom redirect url ``` - id: sign-out title: 'logout()' $ref: '@supabase/gotrue-js.GoTrueClient.signOut' notes: | Logs out the current user. - In order to use the `logout()` method, the user needs to be signed in first. examples: - id: sign-out name: Sign out isSpotlight: true code: | ```kotlin supabase.gotrue.logout() ``` - id: sign-out-all-sessions name: Sign out all sessions isSpotlight: true code: | ```kotlin supabase.gotrue.logout(LogoutScope.GLOBAL) ``` - id: sign-out-others name: Sign out all sessions except the current isSpotlight: true code: | ```kotlin supabase.gotrue.logout(LogoutScope.OTHERS) ``` - id: verify-otp title: 'Verify OTPs' $ref: '@supabase/gotrue-js.GoTrueClient.verifyOtp' notes: | Sign in a user given a User supplied OTP received via mobile. examples: - id: verify-email-otp(otp) name: Verify an Email OTP isSpotlight: true code: | ```kotlin supabase.gotrue.verifyEmailOtp(type = OtpType.Email.INVITE, email = "example@email.com", token = "token") ``` description: | Available types are: - `OtpType.Email.MAGIC_LINK` - `OtpType.Email.SIGNUP` - `OtpType.Email.INVITE` - `OtpType.Email.RECOVERY` - `OtpType.Email.EMAIL_CHANGE` - id: verify-phone-otp(otp) name: Verify an Phone OTP isSpotlight: false code: | ```kotlin supabase.gotrue.verifyPhoneOtp(type = OtpType.Phone.SMS, phoneNumber = "+491234567", token = "token") ``` description: | Available types are: - `OtpType.Phone.SMS` - `OtpType.Phone.PHONE_CHANGE` - id: send-password-reauthentication title: 'reauthenticate()' $ref: '@supabase/gotrue-js.GoTrueClient.reauthenticate' notes: | - This method is used together with `modifyUser()` when a user's password needs to be updated. - This method will send a nonce to the user's email. If the user doesn't have a confirmed email address, the method will send the nonce to the user's confirmed phone number instead. examples: - id: send-reauthentication-nonce name: Send reauthentication nonce description: Sends a reauthentication nonce to the user's email or phone number. isSpotlight: true code: | ```kotlin supabase.gotrue.reauthenticate() ``` - id: resend-email-or-phone-otps title: 'resend()' $ref: '@supabase/gotrue-js.GoTrueClient.resend' notes: | - Resends a signup confirmation, email change or phone change email to the user. - Passwordless sign-ins can be resent by calling the `sendOtpTo()` method again. - Password recovery emails can be resent by calling the `sendRecoveryEmail()` method again. - This method will only resend an email or phone OTP to the user if there was an initial signup, email change or phone change request being made. examples: - id: resend-email-signup-confirmation name: Resend an email signup confirmation description: Resends the email signup confirmation to the user isSpotlight: true code: | ```kotlin supabase.gotrue.resendEmail(OtpType.Email.SIGNUP, "example@email.com") ``` - id: resend-phone-signup-confirmation name: Resend a phone signup confirmation description: Resends the phone signup confirmation email to the user code: | ```kotlin supabase.gotrue.resendPhone(OtpType.Phone.SMS, "1234567890") ``` - id: resend-email-change-email name: Resend email change email description: Resends the email change email to the user code: | ```kotlin supabase.gotrue.resendEmail(OtpType.Email.EMAIL_CHANGE, "example@email.com") ``` - id: resend-phone-change name: Resend phone change OTP description: Resends the phone change OTP to the user code: | ```kotlin supabase.gotrue.resendPhone(OtpType.Phone.PHONE_CHANGE, "1234567890") ``` - id: get-session title: 'Get current session' $ref: '@supabase/gotrue-js.GoTrueClient.getSession' notes: | Returns the current session, or `null` if there is none. examples: - id: get-the-session-data name: Get the session data isSpotlight: true code: | ```kotlin val session = supabase.gotrue.currentSessionOrNull() ``` - id: get-user title: 'getUser()' $ref: '@supabase/gotrue-js.GoTrueClient.getUser' description: | - This method gets the user object from the current session. - Fetches the user object from the database instead of local session. - Should be used only when you require the most current user data. For faster results, `getCurrentSessionOrNull()?.user` is recommended. examples: - id: get-the-logged-in-user-with-the-current-existing-session name: Get the signed-in user with the current session isSpotlight: true code: | ```kotlin val user = supabase.gotrue.retrieveUserForCurrentSession(updateSession = true) ``` description: | `updateSession` updates the local session with the new user - id: get-different-user name: Get a user based on their access token isSpotlight: true code: | ```kotlin val user = supabase.gotrue.retrieveUser("JWT") ``` - id: update-user title: 'modifyUser()' $ref: '@supabase/gotrue-js.GoTrueClient.updateUser' notes: | Modifies the user data. - In order to use the `modifyUser()` method, the user needs to be signed in first. - By default, email updates sends a confirmation link to both the user's current and new email. To only send a confirmation link to the user's new email, disable **Secure email change** in your project's [email auth provider settings](https://supabase.com/dashboard/project/_/auth/providers). examples: - id: update-the-email-for-an-authenticated-user name: Update the email for an authenticated user description: Sends a "Confirm Email Change" email to the new email address. isSpotlight: false code: | ```kotlin val user = supabase.gotrue.modifyUser { email = "newEmail@email.com" } ``` - id: update-the-password-for-an-authenticated-user name: Update the password for an authenticated user isSpotlight: false code: | ```kotlin val user = supabase.gotrue.modifyUser { password = "secretPassword" } ``` - id: update-the-users-metadata name: Update the user's metadata isSpotlight: true code: | ```kotlin val user = supabase.gotrue.modifyUser { data { put("name", "John") } } ``` - id: set-session title: 'importSession()' $ref: '@supabase/gotrue-js.GoTrueClient.setSession' notes: | Changes the local session. - `importSession()` takes in a UserSession. - [Refresh token rotation](/docs/reference/auth/config#refresh_token_rotation_enabled) is enabled by default on all projects to guard against replay attacks. - You can configure the [`REFRESH_TOKEN_REUSE_INTERVAL`](https://supabase.com/docs/reference/auth/config#refresh_token_reuse_interval) which provides a short window in which the same refresh token can be used multiple times in the event of concurrency or offline issues. examples: - id: refresh-the-session name: Set local session description: Sets the local session from refresh_token and returns current session or an error if the refresh_token is invalid. isSpotlight: true code: | ```kotlin supabase.gotrue.importSession(UserSession(accessToken = "token", refreshToken = "refresh", expiresIn = 2000, tokenType = "Bearer", user = null)) ``` - id: refresh-session title: 'refreshSession()' $ref: '@supabase/gotrue-js.GoTrueClient.refreshSession' notes: | This method will refresh the session whether the current one is expired or not. - This is done automatically, but can be disabled in the GoTrue config. examples: - id: refresh-current-session name: Refresh current session isSpotlight: true code: | ```kotlin val session = supabase.gotrue.refreshCurrentSession() ``` - id: refresh-session-using-the-current-session name: Refresh session using the refresh token isSpotlight: true code: | ```kotlin val session = supabase.gotrue.refreshSession(refreshToken = "refreshToken") ``` - id: on-auth-state-change title: 'sessionStatus' $ref: '@supabase/gotrue-js.GoTrueClient.onAuthStateChange' notes: | Listen to session changes. examples: - id: listen-to-auth-changes name: Listen to auth changes isSpotlight: true code: | ```kotlin supabase.gotrue.sessionStatus.collect { when(it) { is SessionStatus.Authenticated -> println(it.session.user) SessionStatus.LoadingFromStorage -> println("Loading from storage") SessionStatus.NetworkError -> println("Network error") SessionStatus.NotAuthenticated -> println("Not authenticated") } } ``` description: | Types of statuses: - `NotAuthenticated`, - `LoadingFromStorage`, - `NetworkError`, - `Authenticated(session)` - id: reset-password-for-email title: 'Send a password reset request' notes: | Sends a password reset request to the given email address. - The password reset flow consists of 2 broad steps: (i) Allow the user to sign in via the password reset link; (ii) Update the user's password. - The `sendRecoveryEmail()` only sends a password reset link to the user's email. To update the user's password, see [`modifyUser()`](/docs/reference/kotlin/auth-updateuser). - The user gets redirected back to your app, assuming you setup [OTP handling](/docs/reference/kotlin/initializing) - After the user has been redirected successfully, prompt them for a new password and call `modifyUser()`: ```kotlin supabase.gotrue.modifyUser { password = "1234567" } ``` examples: - id: send-password-reset-email name: Send password reset email isSpotlight: true code: | ```kotlin supabase.gotrue.sendRecoveryEmail(email = "example@email.com") ``` - id: exchange-code-for-session title: 'exchangeCodeForSession()' $ref: '@supabase/gotrue-js.GoTrueClient.exchangeCodeForSession' notes: | - Used when `flowType` is set to `FlowType.PKCE` in the GoTrue configuration. examples: - id: exchange-auth-code name: Exchange Auth Code isSpotlight: true code: | ```kotlin supabase.gotrue.exchangeCodeForSession("34e770dd-9ff9-416c-87fa-43b31d7ef225") ``` - id: auth-mfa-api title: 'Overview' notes: | This section contains methods commonly used for Multi-Factor Authentication (MFA) and are invoked behind the `supabase.gotrue.mfa` namespace. Currently, we only support time-based one-time password (TOTP) as the 2nd factor. We don't support recovery codes but we allow users to enroll more than 1 TOTP factor, with an upper limit of 10. Having a 2nd TOTP factor for recovery frees the user of the burden of having to store their recovery codes somewhere. It also reduces the attack surface since multiple recovery codes are usually generated compared to just having 1 backup TOTP factor. - id: mfa-enroll title: 'Enroll a factor' $ref: '@supabase/gotrue-js.GoTrueMFAApi.enroll' notes: | Enrolls a new factor. - Currently, `totp` is the only supported `factorType`. The returned `id` should be used to create a challenge. - To create a challenge, see [`mfa.createChallenge()`](/docs/reference/kotlin/auth-mfa-challenge). - To verify a challenge, see [`mfa.verifyChallenge()`](/docs/reference/kotlin/auth-mfa-verify). - To create and verify a challenge in a single step, see [`mfa.createChallengeAndVerify()`](/docs/reference/kotlin/auth-mfa-challengeandverify). examples: - id: enroll-totp-factor name: Enroll a time-based, one-time password (TOTP) factor isSpotlight: true code: | ```kotlin val factor = supabase.gotrue.mfa.enroll(factorType = FactorType.TOTP) // Use the id to create a challenge. // The challenge can be verified by entering the code generated from the authenticator app. // The code will be generated upon scanning the qr_code or entering the secret into the authenticator app. val (id, type, qrCode) = factor.data //qrCode is a svg as a string val (factorId, factorType, _) = factor ``` - id: get-local-verified-factors name: Check the local user for verified factors isSpotlight: true code: | ```kotlin val verifiedFactors = supabase.gotrue.mfa.verifiedFactors ``` - id: retrieve-verified-factors name: Retrieve verified factors isSpotlight: true code: | ```kotlin val verifiedFactors = supabase.gotrue.mfa.retrieveFactorsForCurrentUser() ``` - id: mfa-challenge title: 'mfa.challenge()' $ref: '@supabase/gotrue-js.GoTrueMFAApi.challenge' notes: | Creates a challenge for a factor. - An [enrolled factor](/docs/reference/kotlin/auth-mfa-enroll) is required before creating a challenge. - To verify a challenge, see [`mfa.verifyChallenge()`](/docs/reference/kotlin/auth-mfa-verify). examples: - id: create-mfa-challenge name: Create a challenge for a factor isSpotlight: true code: | ```kotlin val challenge = supabase.gotrue.mfa.createChallenge(factorId = "34e770dd-9ff9-416c-87fa-43b31d7ef225") ``` - id: mfa-verify title: 'mfa.verify()' $ref: '@supabase/gotrue-js.GoTrueMFAApi.verify' notes: | Verifies a challenge for a factor. - To verify a challenge, please [create a challenge](/docs/reference/kotlin/auth-mfa-challenge) first. examples: - id: verify-challenge name: Verify a challenge for a factor isSpotlight: true code: | ```kotlin supabase.gotrue.mfa.verifyChallenge( factorId = "34e770dd-9ff9-416c-87fa-43b31d7ef225", challengeId = "4034ae6f-a8ce-4fb5-8ee5-69a5863a7c15", code = "123456", saveSession = true // this is set to true by default, but you can set it to false if you want to handle the session yourself ) ``` - id: mfa-challenge-and-verify title: 'mfa.challengeAndVerify()' $ref: '@supabase/gotrue-js.GoTrueMFAApi.challengeAndVerify' notes: | Creates and verifies a challenge for a factor. - An [enrolled factor](/docs/reference/kotlin/auth-mfa-enroll) is required before invoking `createChallengeAndVerify()`. - Executes [`mfa.createChallenge()`](/docs/reference/kotlin/auth-mfa-challenge) and [`mfa.verifyChallenge()`](/docs/reference/kotlin/auth-mfa-verify) in a single step. examples: - id: challenge-and-verify name: Create and verify a challenge for a factor isSpotlight: true code: | ```kotlin supabase.gotrue.mfa.createChallengeAndVerify( factorId = "34e770dd-9ff9-416c-87fa-43b31d7ef225", code = "123456", saveSession = true // this is set to true by default, but you can set it to false if you want to handle the session yourself ) ``` - id: mfa-unenroll title: 'mfa.unenroll()' $ref: '@supabase/gotrue-js.GoTrueMFAApi.unenroll' notes: | Unenroll removes a MFA factor. A user has to have an `AAL2` authentication level in order to unenroll a verified factor. examples: - id: unenroll-a-factor name: Unenroll a factor isSpotlight: true code: | ```kotlin supabase.gotrue.mfa.unenroll(factorId = "34e770dd-9ff9-416c-87fa-43b31d7ef225") ``` - id: mfa-get-authenticator-assurance-level title: 'mfa.getAuthenticatorAssuranceLevel()' $ref: '@supabase/gotrue-js.GoTrueMFAApi.getAuthenticatorAssuranceLevel' notes: | - Authenticator Assurance Level (AAL) is the measure of the strength of an authentication mechanism. - In Supabase, having an AAL of `aal1` refers to having the 1st factor of authentication such as an email and password or OAuth sign-in while `aal2` refers to the 2nd factor of authentication such as a time-based, one-time-password (TOTP). - If the user has a verified factor, the `next` field will return `AuthenticatorAssuranceLevel.AAL2`, else, it will return `AuthenticatorAssuranceLevel.AAL1`. examples: - id: get-aal name: Get the AAL details of the current session isSpotlight: true code: | ```kotlin val (current, next) = supabase.gotrue.mfa.getAuthenticatorAssuranceLevel() ``` - id: aal-enabled name: Check whether the user has at least one verified factor isSpotlight: true code: | ```kotlin val enabled = supabase.gotrue.mfa.isMfaEnabled //flow variant, automatically emitting new values on session changes val enabledFlow = supabase.gotrue.mfa.isMfaEnabledFlow ``` - id: aal-enabled-for-current-session name: Check whether the user is signed in using AAL2 isSpotlight: true code: | ```kotlin val loggedInUsingMfa = supabase.gotrue.mfa.loggedInUsingMfa //flow variant, automatically emitting new values on session changes val loggedInUsingMfaFlow = supabase.gotrue.mfa.loggedInUsingMfaFlow ``` - id: admin-api title: 'Overview' notes: | - Any method under the `supabase.gotrue.admin` namespace requires a `service_role` key. - These methods are considered admin methods and should be called on a trusted server. Never expose your `service_role` key in the browser. examples: - id: create-auth-admin-client name: Create server-side auth client isSpotlight: true code: | ```kotlin val supabase = createSupabaseClient( supabaseUrl = "https://id.supabase.co", supabaseKey = "supabaseKey" ) { install(GoTrue) { autoLoadFromStorage = false alwaysAutoRefresh = false } // install other plugins (these will use the service role key) } supabase.gotrue.importAuthToken("service_role") // Access auth admin api val adminGoTrueClient = supabase.gotrue.admin ``` - id: get-user-by-id title: 'getUserById()' $ref: '@supabase/gotrue-js.GoTrueAdminApi.getUserById' notes: | Fetches the user object from the database based on the user's id. - The `retrieveUserById()` method requires the user's id which maps to the `auth.users.id` column. examples: - id: fetch-the-user-object-using-the-access-token-jwt name: Fetch the user object using the access_token jwt isSpotlight: true code: | ```kotlin val user = supabase.gotrue.admin.retrieveUserById(uid = "f2a0b0a0-6b1a-4b7a-8f1a-4b7a6b1a8f1a") ``` - id: list-users title: 'listUsers()' $ref: '@supabase/gotrue-js.GoTrueAdminApi.listUsers' notes: | Retrieves a list of users. - Defaults to return 50 users per page. examples: - id: get-a-full-list-of-users name: Get a page of users isSpotlight: true code: | ```kotlin val users = supabase.gotrue.admin.retrieveUsers() ``` - id: get-paginated-list-of-users name: Paginated list of users isSpotlight: false code: | ```kotlin val users = supabase.gotrue.admin.retrieveUsers( page = 1, perPage = 100 ) ``` - id: create-user title: 'createUser()' $ref: '@supabase/gotrue-js.GoTrueAdminApi.createUser' notes: | Creates a new user. - To confirm the user's email address or phone number, set `autoConfirm` to true. Both arguments default to false. examples: - id: create-a-new-user-with-email-custom-user-metadata name: Create user with email isSpotlight: true code: | ```kotlin val userWithEmail = supabase.gotrue.admin.createUserWithEmail { email = "example@email.com" password = "secretpassword" userMetadata { put("name", "John") } } ``` - id: create-a-new-user-with-phone-custom-user-metadata name: Create user with phone isSpotlight: true code: | ```kotlin val userWithPhone = supabase.gotrue.admin.createUserWithPhone { phoneNumber = "+49123456789" password = "secretpassword" userMetadata { put("name", "John") } } ``` - id: auto-confirm-the-users-email name: Auto-confirm the user's email code: | ```kotlin val userWithEmail = supabase.gotrue.admin.createUserWithEmail { email = "example@email.com" password = "secretpassword" autoConfirm = true } ``` - id: auto-confirm-the-users-phone-number name: Auto-confirm the user's phone number code: | ```kotlin val userWithPhone = supabase.gotrue.admin.createUserWithPhone { phoneNumber = "+49123456789" password = "secretpassword" autoConfirm = true } ``` - id: delete-user title: 'deleteUser()' $ref: '@supabase/gotrue-js.GoTrueAdminApi.deleteUser' notes: | Deletes a user from the database. - The `deleteUser()` method requires the user's ID, which maps to the `auth.users.id` column. examples: - id: removes-a-user name: Removes a user isSpotlight: true code: | ```kotlin supabase.gotrue.admin.deleteUser(uid = "uid") ``` - id: invite-user-by-email title: 'inviteUserByEmail()' $ref: '@supabase/gotrue-js.GoTrueAdminApi.inviteUserByEmail' notes: | Sends an invite link to the user's email address. examples: - id: invite-a-user name: Invite a user isSpotlight: true code: | ```kotlin supabase.gotrue.admin.inviteUserByEmail( email = "example@email.com", //optional: redirectTo = "https://example.com/redirect", data = buildJsonObject { put("custom", "value") } ) ``` - id: generate-link title: 'generateLink()' $ref: '@supabase/gotrue-js.GoTrueAdminApi.generateLink' notes: | Generates email links and OTPs. This will not send links or OTPs to the end user. This function is for custom admin functionality. examples: - id: generate-a-signup-link name: Generate a signup link isSpotlight: true code: | ```kotlin val (url, user) = supabase.gotrue.admin.generateLinkFor(LinkType.Signup) { email = "example@email.com" password = "secretpassword" } ``` - id: generate-an-invite-link name: Generate an invite link isSpotlight: false code: | ```kotlin val (url, user) = supabase.gotrue.admin.generateLinkFor(LinkType.Invite) { email = "example@email.com" } ``` - id: generate-a-magic-link name: Generate a magic link isSpotlight: false code: | ```kotlin val (url, user) = supabase.gotrue.admin.generateLinkFor(LinkType.MagicLink) { email = "example@email.com" } ``` - id: generate-a-recovery-link name: Generate a recovery link isSpotlight: false code: | ```kotlin val (url, user) = supabase.gotrue.admin.generateLinkFor(LinkType.Recovery) { email = "example@email.com" } ``` - id: generate-links-to-change-current-email-address name: Generate links to change current email address isSpotlight: false code: | ```kotlin // generate an email change link to be sent to the current email address val (url, user) = supabase.gotrue.admin.generateLinkFor(LinkType.EmailChangeCurrent) { email = "example@email.com" newEmail = "newEmail@email.com" } // generate an email change link to be sent to the new email address val (url, user) = supabase.gotrue.admin.generateLinkFor(LinkType.EmailChangeNew) { email = "example@email.com" newEmail = "newEmail@email.com" } ``` - id: update-user-by-id title: 'updateUserById()' $ref: '@supabase/gotrue-js.GoTrueAdminApi.updateUserById' notes: | Updates the user data. examples: - id: updates-a-users-email name: Updates a user's email isSpotlight: false code: | ```kotlin supabase.gotrue.admin.updateUserById(uid = "id") { email = "example@email.com" } ``` - id: updates-a-users-password name: Updates a user's password isSpotlight: false code: | ```js supabase.gotrue.admin.updateUserById(uid = "id") { password = "password" } ``` - id: updates-a-users-metadata name: Updates a user's metadata isSpotlight: true code: | ```kotlin supabase.gotrue.admin.updateUserById(uid = "id") { userMetadata = buildJsonObject { put("key", "value") } } ``` - id: updates-a-users-app-metadata name: Updates a user's app_metadata isSpotlight: false code: | ```kotlin supabase.gotrue.admin.updateUserById(uid = "id") { appMetadata = buildJsonObject { put("key", "value") } } ``` - id: confirms-a-users-email-address name: Confirms a user's email address isSpotlight: false code: | ```kotlin supabase.gotrue.admin.updateUserById(uid = "id") { emailConfirm = true } ``` - id: confirms-a-users-phone-number name: Confirms a user's phone number isSpotlight: false code: | ```kotlin supabase.gotrue.admin.updateUserById(uid = "id") { phoneConfirm = true } ``` - id: mfa-list-factors title: 'mfa.listFactors()' notes: | Lists all factors associated to a user. $ref: '@supabase/gotrue-js.GoTrueAdminMFAApi.listFactors' examples: - id: list-factors name: List all factors for a user isSpotlight: true code: | ```kotlin const factors = supabase.gotrue.admin.retrieveFactors(uid = "id") ``` - id: mfa-delete-factor title: 'mfa.deleteFactor()' $ref: '@supabase/gotrue-js.GoTrueAdminMFAApi.deleteFactor' notes: | Deletes a factor on a user. This will log the user out of all active sessions if the deleted factor was verified. examples: - id: delete-factor name: Delete a factor for a user isSpotlight: true code: | ```kotlin supabase.gotrue.admin.deleteFactor(uid = "id", factorId = "factor_id") ``` - id: invoke title: 'invoke()' description: | Invokes a Supabase Function. See the [guide](/docs/guides/functions) for details on writing Functions. - When invoking a function with parameters, you have to provide a [serializable value](/docs/reference/kotlin/installing#serialization) in the function parameter. notes: | - Requires an Authorization header. examples: - id: basic-invocation name: Basic invocation isSpotlight: true code: | ```kotlin supabase.functions.invoke("function_name") ``` - id: basic-invocation-with-body name: Basic invocation with body isSpotlight: true code: | ```kotlin supabase.functions.invoke( function = "function_name", body = buildJsonObject { put("foo", "bar") }, headers = Headers.build { append(HttpHeaders.ContentType, "application/json") } ) ``` - id: reuse-function name: Reuse function by saving it to a variable isSpotlight: true code: | ```kotlin val function = supabase.functions.buildEdgeFunction( function = "function", headers = Headers.build { /*Default headers*/ //when you are sending a body you may want to add this header: append(HttpHeaders.ContentType, "application/json") } ) //invoke it: function() //invoke it with a body: function(body) //invoke it with custom request options: function(body) { header("Header", "Value") parameter("Key", "Value") //url parameter } ``` - id: subscribe description: | Subscribe to realtime changes in your database. title: 'on().subscribe()' notes: | - Realtime is disabled by default for new Projects for better database performance and security. You can turn it on by [managing replication](/docs/guides/api). - If you want to receive the "previous" data for updates and deletes, you will need to set `REPLICA IDENTITY` to `FULL`, like this: `ALTER TABLE your_table REPLICA IDENTITY FULL;` - When using a method with a generic type like `track`, `broadcast` or `broadcastFlow`, you have to provide a [serializable class](/docs/reference/kotlin/installing#serialization) as the type parameter. examples: - id: connect-to-realtime-client name: Connect to Realtime isSpotlight: true code: | ```kotlin supabase.realtime.connect() ``` - id: liste-to-broadcasts name: Listen to broadcasts code: | ```kotlin @Serializable data class Message(val content: String, val sender: String) val channel = supabase.realtime.createChannel("channelId") { //optional config } val broadcastFlow = channel.broadcastFlow(event = "message") //in a new coroutine (or use Flow.onEach().launchIn(scope)): broadcastFlow.collect { //it: Message println(it) } supabase.realtime.connect() channel.join(blockUntilJoined = true) channel.broadcast(event = "message", Message("I joined!", "John")) ``` - id: listen-to-presence-updates name: Listen to presence updates code: | ```kotlin @Serializable data class PresenceState(val username: String) val connectedUsers = mutableSetOf() val channel = supabase.realtime.createChannel("channelId") { //optional config } val presenceChangeFlow = channel.presenceChangeFlow() //in a new coroutine (or use Flow.onEach().launchIn(scope)): presenceChangeFlow.collect { connectedUsers += it.decodeJoinsAs() connectedUsers -= it.decodeLeavesAs() } supabase.realtime.connect() channel.join(blockUntilJoined = true) //send own state channel.track(PresenceState(username = "John")) - id: listen-to-all-database-changes name: Listen to all database changes code: | ```kotlin val channel = supabase.realtime.createChannel("channelId") { //optional config } val changeFlow = channel.postgresChangeFlow(schema = "public") //in a new coroutine (or use Flow.onEach().launchIn(scope)): changeFlow.collect { when(it) { is PostgresAction.Delete -> println("Deleted: ${it.oldRecord}") is PostgresAction.Insert -> println("Inserted: ${it.record}") is PostgresAction.Select -> println("Selected: ${it.record}") is PostgresAction.Update -> println("Updated: ${it.oldRecord} with ${it.record}") } } supabase.realtime.connect() channel.join() ``` - id: listen-to-a-specific-table name: Listen to a specific table code: | ```kotlin val channel = supabase.realtime.createChannel("channelId") { //optional config } val changeFlow = channel.postgresChangeFlow(schema = "public") { table = "users" } //in a new coroutine (or use Flow.onEach().launchIn(scope)): changeFlow.collect { when(it) { is PostgresAction.Delete -> println("Deleted: ${it.oldRecord}") is PostgresAction.Insert -> println("Inserted: ${it.record}") is PostgresAction.Select -> println("Selected: ${it.record}") is PostgresAction.Update -> println("Updated: ${it.oldRecord} with ${it.record}") } } supabase.realtime.connect() channel.join() ``` - id: listen-to-inserts name: Listen to inserts code: | ```kotlin val channel = supabase.realtime.createChannel("channelId") { //optional config } val changeFlow = channel.postgresChangeFlow(schema = "public") { table = "users" } //in a new coroutine (or use Flow.onEach().launchIn(scope)): changeFlow.collect { println(it.record) } supabase.realtime.connect() channel.join() ``` - id: listen-to-updates name: Listen to updates description: | By default, Supabase will send only the updated record. If you want to receive the previous values as well you can enable full replication for the table you are listening too: ```sql alter table "your_table" replica identity full; ``` code: | ```kotlin val channel = supabase.realtime.createChannel("channelId") { //optional config } val changeFlow = channel.postgresChangeFlow(schema = "public") { table = "users" } //in a new coroutine (or use Flow.onEach().launchIn(scope)): changeFlow.collect { println(it.record) println(it.oldRecord) } supabase.realtime.connect() channel.join() ``` - id: listen-to-deletes name: Listen to deletes description: | By default, Supabase does not send deleted records. If you want to receive the deleted record you can enable full replication for the table you are listening too: ```sql alter table "your_table" replica identity full; ``` code: | ```kotlin val channel = supabase.realtime.createChannel("channelId") { //optional config } val changeFlow = channel.postgresChangeFlow(schema = "public") { table = "users" } //in a new coroutine (or use Flow.onEach().launchIn(scope)): changeFlow.collect { println(it.oldRecord) } supabase.realtime.connect() channel.join() ``` - id: listening-to-row-level-changes name: Listen to row level changes description: You can listen to individual rows using the format `{table}:{col}=eq.{val}` - where `{col}` is the column name, and `{val}` is the value which you want to match. code: | ```kotlin val channel = supabase.realtime.createChannel("channelId") { //optional config } val changeFlow = channel.postgresChangeFlow(schema = "public") { table = "users" filter = "id=eq.1" } //in a new coroutine: changeFlow.collect { println(it.oldRecord) } supabase.realtime.connect() channel.join() ``` - id: remove-channel description: | Unsubscribes and removes Realtime channel from Realtime client. title: 'removeChannel()' notes: | - Removing a channel is a great way to maintain the performance of your project's Realtime service as well as your database if you're listening to Postgres changes. - Supabase will automatically handle cleanup 30 seconds after a client is disconnected, but unused channels may cause degradation as more clients are simultaneously subscribed. examples: - id: removes-a-channel name: Remove a channel isSpotlight: true code: | ```kotlin val channel = supabase.realtime.createChannel("channelId") { //optional config } //... supabase.realtime.removeChannel(channel) ``` - id: unsubscribe-channel name: Unsubscribe from a channel isSpotlight: true code: | ```kotlin val channel = supabase.realtime.createChannel("channelId") { //optional config } //... channel.leave() ``` - id: remove-all-channels title: removeAllChannels() $ref: '@supabase/supabase-js.index.SupabaseClient.removeAllChannels' notes: | Unsubscribes and removes all Realtime channels from Realtime client. - Removing channels is a great way to maintain the performance of your project's Realtime service as well as your database if you're listening to Postgres changes. Supabase will automatically handle cleanup 30 seconds after a client is disconnected, but unused channels may cause degradation as more clients are simultaneously subscribed. examples: - id: remove-all-channels name: Remove all channels isSpotlight: true code: | ```kotlin supabase.realtime.removeAllChannels() ``` - id: get-channels title: getChannels() $ref: '@supabase/supabase-js.index.SupabaseClient.getChannels' notes: | Returns all Realtime channels. examples: - id: get-all-channels name: Get all channels isSpotlight: true code: | ```kotlin val channels = supabase.realtime.subscriptions.entries ``` - id: file-buckets title: 'Overview' notes: | This section contains methods for working with File Buckets. # - id: analytics-buckets # title: 'Overview' # notes: | # This section contains methods for working with Analytics Buckets. # - id: vector-buckets # title: 'Overview' # notes: | # This section contains methods for working with Vector Buckets. - id: list-buckets title: listBuckets() $ref: '@supabase/storage-js.packages/StorageBucketApi.default.listBuckets' notes: | - RLS policy permissions required: - `buckets` table permissions: `select` - `objects` table permissions: none - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works examples: - id: list-buckets name: List buckets isSpotlight: true code: | ```kotlin val buckets = supabase.storage.retrieveBuckets() ``` - id: get-bucket title: getBucket() $ref: '@supabase/storage-js.packages/StorageBucketApi.default.getBucket' notes: | - RLS policy permissions required: - `buckets` table permissions: `select` - `objects` table permissions: none - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works examples: - id: get-bucket name: Get bucket isSpotlight: true code: | ```kotlin val bucket = supabase.storage.retrieveBucketById(bucketId = "avatars") ``` - id: create-bucket title: createBucket() $ref: '@supabase/storage-js.packages/StorageBucketApi.default.createBucket' notes: | - RLS policy permissions required: - `buckets` table permissions: `insert` - `objects` table permissions: none - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works examples: - id: create-bucket name: Create bucket isSpotlight: true code: | ```kotlin supabase.storage.createBucket(name = "icons", id = "icons") { public = true fileSizeLimit = 5.megabytes } ``` - id: update-bucket title: updateBucket() $ref: '@supabase/storage-js.packages/StorageBucketApi.default.updateBucket' notes: | - RLS policy permissions required: - `buckets` table permissions: `select` and `update` - `objects` table permissions: none - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works examples: - id: update-bucket name: Update bucket isSpotlight: true code: | ```kotlin supabase.storage.updateBucket("cards") { public = false fileSizeLimit = 20.megabytes allowedMimeTypes(ContentType.Image.PNG, ContentType.Image.JPEG) } ``` - id: empty-bucket title: emptyBucket() $ref: '@supabase/storage-js.packages/StorageBucketApi.default.emptyBucket' notes: | - RLS policy permissions required: - `buckets` table permissions: `select` - `objects` table permissions: `select` and `delete` - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works examples: - id: empty-bucket name: Empty bucket isSpotlight: true code: | ```kotlin supabase.storage.emptyBucket(bucketId = "icons") ``` - id: delete-bucket title: deleteBucket() $ref: '@supabase/storage-js.packages/StorageBucketApi.default.deleteBucket' notes: | - RLS policy permissions required: - `buckets` table permissions: `select` and `delete` - `objects` table permissions: none - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works examples: - id: delete-bucket name: Delete bucket isSpotlight: true code: | ```kotlin supabase.storage.deleteBucket(bucketId = "icons") ``` - id: from-upload title: from.upload() $ref: '@supabase/storage-js.packages/StorageFileApi.default.upload' notes: | - RLS policy permissions required: - `buckets` table permissions: none - `objects` table permissions: `insert` - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works - Resumable uploads use a `Disk` cache by default to store the upload urls. You can customize that in the GoTrue config by changing the `resumable.cache` property. examples: - id: upload-file name: Upload file isSpotlight: true code: | ```kotlin val bucket = supabase.storage["avatars"] bucket.upload("myIcon.png", byteArray, upsert = false) //on JVM you can use java.io.File bucket.upload("myIcon.png", file, upsert = false) ``` - id: upload-file-with-progress name: Upload file with progress isSpotlight: true code: | ```kotlin val bucket = supabase.storage["avatars"] bucket.uploadAsFlow("test.png", byteArrayOf()).collect { when(it) { is UploadStatus.Progress -> println("Progress: ${it.totalBytesSend.toFloat() / it.contentLength * 100}%") is UploadStatus.Success -> println("Success") } } ``` - id: create-resumable-upload name: Create resumable upload isSpotlight: true code: | ```kotlin val bucket = supabase.storage["avatars"] //JVM/Android: val upload = bucket.resumable.createOrContinueUpload("icon.png", File("icon.png")) //Other platforms: val upload = bucket.resumable.createOrContinueUpload(data = byteArray, source = "this is for continuing previous uploads later", path = "icon.png") val upload = bucket.resumable.createOrContinueUpload( //Probably better to write an extension function channel = { offset -> /* create ByteReadChannel and seek to offset */ }, source = "this is for continuing previous uploads later", size = dataSize, path = "icon.png" ) ``` - id: start-resumable-upload name: Start and resumable upload isSpotlight: true code: | ```kotlin upload.startOrResumeUploading() ``` - id: pause-resumable-upload name: Pause resumable upload code: | ```kotlin upload.pause() ``` - id: cancel-resumable-upload name: Cancel resumable upload code: | ```kotlin upload.cancel() ``` description: | This will also remove the upload url from the cache - id: listen-to-upload-state name: Listen to the resumable upload state code: | ```kotlin upload.stateFlow.collect { println("Progress: ${it.progress * 100}%") println("Paused: ${it.paused}") println("Is done: ${it.isDone}") } ``` - id: continue-previous-upload name: Continue previous uploads isSpotlight: true code: | ```kotlin val bucket = supabase.storage["avatars"] //only on JVM/Android: bucket.resumable.continuePreviousFileUploads() .map { it.await() } //await all uploads. This just makes sure the uploads have an update-to-date url. You can also do this in parallel .forEach { upload -> upload.startOrResumeUploading() } //on other platforms you may have to continue uploads from the source (Probably better to write an extension function): bucket.resumable.continuePreviousUploads { source, offset -> //create ByteReadChannel from source and seek to offset } .map { it.await() } //await all uploads. This just makes sure the uploads have an update-to-date url. You can also do this in parallel .forEach { upload -> upload.startOrResumeUploading() } ``` - id: from-update title: from.update() $ref: '@supabase/storage-js.packages/StorageFileApi.default.update' notes: | - RLS policy permissions required: - `buckets` table permissions: none - `objects` table permissions: `update` and `select` - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works examples: - id: update-file name: Update file isSpotlight: true code: | ```kotlin val bucket = supabase.storage["avatars"] bucket.update("myIcon.png", byteArray, upsert = false) //on JVM you can use java.io.File bucket.update("myIcon.png", file, upsert = false) ``` - id: from-move title: from.move() $ref: '@supabase/storage-js.packages/StorageFileApi.default.move' notes: | - RLS policy permissions required: - `buckets` table permissions: none - `objects` table permissions: `update` and `select` - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works examples: - id: move-file name: Move file isSpotlight: true code: | ```kotlin val bucket = supabase.storage["avatars"] bucket.move("icon1.png", "icon2.png") ``` - id: from-copy title: from.copy() $ref: '@supabase/storage-js.packages/StorageFileApi.default.copy' notes: | - RLS policy permissions required: - `buckets` table permissions: none - `objects` table permissions: `insert` and `select` - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works examples: - id: copy-file name: Copy file isSpotlight: true code: | ```kotlin supabase.storage["test"].copy(from = "avatar.png", to = "avatar2.png") ``` - id: from-create-signed-url title: from.createSignedUrl() $ref: '@supabase/storage-js.packages/StorageFileApi.default.createSignedUrl' notes: | - RLS policy permissions required: - `buckets` table permissions: none - `objects` table permissions: `select` - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works examples: - id: create-signed-url name: Create Signed URL isSpotlight: true code: | ```kotlin val bucket = supabase.storage["avatars"] val url = bucket.createSignedUrl(path = "icon.png", expiresIn = 3.minutes) ``` - id: create-signed-url-with-transformation name: Create Signed URL with transformation code: | ```kotlin val bucket = supabase.storage["avatars"] val url = bucket.createSignedUrl(path = "icon.png", expiresIn = 3.minutes) { size(100, 100) fill() quality = 80 } ``` - id: from-create-signed-urls title: from.createSignedUrls() notes: | - RLS policy permissions required: - `buckets` table permissions: none - `objects` table permissions: `select` - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works examples: - id: create-signed-urls name: Create Signed URLs isSpotlight: true code: | ```kotlin val urls = supabase.storage["avatars"].createSignedUrls(20.minutes, "avata1.jpg", "avatar2.jpg") ``` - id: from-create-signed-upload-url title: from.createSignedUploadUrl() $ref: '@supabase/storage-js.packages/StorageFileApi.default.createSignedUploadUrl' notes: | - RLS policy permissions required: - `buckets` table permissions: none - `objects` table permissions: `insert` - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works examples: - id: create-signed-upload-url name: Create Signed Upload URL isSpotlight: true code: | ```kotlin val url = supabase.storage["avatars"].createSignedUploadUrl("avatar.png") ``` - id: from-upload-to-signed-url title: from.uploadToSignedUrl() $ref: '@supabase/storage-js.packages/StorageFileApi.default.uploadToSignedUrl' notes: | - RLS policy permissions required: - `buckets` table permissions: none - `objects` table permissions: none - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works examples: - id: upload-to-signed-url name: Upload to a signed URL isSpotlight: true code: | ```kotlin supabase.storage["avatars"].uploadToSignedUrl(path = "avatar.jpg", token = "token-from-createSignedUploadUrl", data = bytes) //or on JVM: supabase.storage["avatars"].uploadToSignedUrl(path = "avatar.jpg", token = "token-from-createSignedUploadUrl", file = File("avatar.jpg")) ``` - id: from-get-public-url title: from.getPublicUrl() $ref: '@supabase/storage-js.packages/StorageFileApi.default.getPublicUrl' notes: | - The bucket needs to be set to public, either via [updateBucket()](/docs/reference/kotlin/storage-updatebucket) or by going to Storage on [supabase.com/dashboard](https://supabase.com/dashboard), clicking the overflow menu on a bucket and choosing "Make public" - RLS policy permissions required: - `buckets` table permissions: none - `objects` table permissions: none - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works examples: - id: returns-the-url-for-an-asset-in-a-public-bucket name: Returns the URL for an asset in a public bucket isSpotlight: true code: | ```kotlin val url = supabase.storage["public-bucket"].publicUrl("folder/avatar1.png") ``` - id: transform-asset-in-public-bucket name: Returns the URL for an asset in a public bucket with transformations isSpotlight: true code: | ```kotlin val url = supabase.storage["public-bucket"].publicRenderUrl("folder/avatar1.png") { size(100, 100) } ``` - id: from-download title: from.download() $ref: '@supabase/storage-js.packages/StorageFileApi.default.download' notes: | - RLS policy permissions required: - `buckets` table permissions: none - `objects` table permissions: `select` - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works examples: - id: download-file-authenticated name: Download file from non-public bucket isSpotlight: true code: | ```kotlin val bucket = supabase.storage["avatars"] val bytes = bucket.downloadAuthenticated("test.png") //or on JVM: bucket.downloadAuthenticatedTo("test.png", File("test.png")) ``` - id: download-file-public name: Download file from public bucket isSpotlight: true code: | ```kotlin val bucket = supabase.storage["avatars"] val bytes = bucket.downloadPublic("test.png") //or on JVM: bucket.downloadPublicTo("test.png", File("test.png")) ``` - id: download-with-transformation name: Download file with transformation code: | ```kotlin val bucket = supabase.storage["avatars"] val bytes = bucket.downloadPublic("test.png") { size(100, 100) fill() quality = 100 } //or on JVM: bucket.downloadPublicTo("test.png", File("test.png")) { size(100, 100) fill() quality = 100 } ``` - id: download-with-progress name: Download file with progress code: | ```kotlin val bucket = supabase.storage["avatars"] bucket.downloadAuthenticatedAsFlow("icon.png").collect { when(it) { is DownloadStatus.ByteData -> println("Downloaded ${it.data.size} bytes") is DownloadStatus.Progress -> println("Downloaded ${it.totalBytesReceived.toFloat() / it.contentLength * 100}%") DownloadStatus.Success -> println("Downloaded successfully") } } //or on JVM: bucket.downloadAuthenticatedToAsFlow("icon.png", File("icon.png")).collect { when(it) { is DownloadStatus.Progress -> println("Downloaded ${it.totalBytesReceived.toFloat() / it.contentLength * 100}%") DownloadStatus.Success -> println("Downloaded successfully") else -> {} //The ByteData status will never occur as we are writing directly to a file } } ``` - id: from-remove title: from.remove() $ref: '@supabase/storage-js.packages/StorageFileApi.default.remove' notes: | - RLS policy permissions required: - `buckets` table permissions: none - `objects` table permissions: `delete` and `select` - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works examples: - id: delete-file name: Delete file isSpotlight: true code: | ```kotlin val bucket = supabase.storage["avatars"] bucket.delete("test.png", "test2.png") ``` - id: from-list title: from.list() $ref: '@supabase/storage-js.packages/StorageFileApi.default.list' notes: | - RLS policy permissions required: - `buckets` table permissions: none - `objects` table permissions: `select` - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works examples: - id: list-files-in-a-bucket name: List files in a bucket isSpotlight: true code: | ```kotlin val bucket = supabase.storage["avatars"] val files = bucket.list() ```