Files
supabase/apps/docs/content/guides/auth/managing-user-data.mdx
Guillaume Faas 94bc3f8d07 docs(csharp): add C# snippets (#48537)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Documentation**
* Added C# examples across API, authentication, database, Realtime, and
Storage guides.
* Expanded authentication coverage for passwordless, phone, anonymous,
identity linking, SSO, sign-out, and social login providers.
* Added database examples for queries, functions, joins, JSON, arrays,
search, PostGIS, and custom schemas.
* Added Realtime examples for broadcasts, presence, subscriptions, and
database changes.
* Added Storage examples for buckets, uploads, downloads,
transformations, CDN purging, and resumable transfers.
  * Included C# error-handling guidance and relevant reference links.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-03 13:13:55 +02:00

264 lines
8.0 KiB
Plaintext

---
id: 'user-management'
title: 'User Management'
subtitle: 'View, delete, and export user information.'
---
You can view your users on the [Users page](/dashboard/project/_/auth/users) of the Dashboard. You can also view the contents of the Auth schema in the [Table Editor](/dashboard/project/_/editor).
## Accessing user data via API
For security, the Auth schema is not exposed in the auto-generated API. If you want to access users data via the API, you can create your own user tables in the `public` schema.
Make sure to protect the table by enabling [Row Level Security](/docs/guides/database/postgres/row-level-security) and only granting the necessary privileges for each role. Reference the `auth.users` table to ensure data integrity. Specify `on delete cascade` in the reference. For example, a `public.profiles` table might look like this:
```sql
create table public.profiles (
id uuid not null references auth.users on delete cascade,
first_name text,
last_name text,
primary key (id)
);
-- Grant the privileges the roles need
GRANT SELECT ON public.profiles TO anon;
GRANT SELECT, INSERT, UPDATE, DELETE ON public.profiles TO authenticated;
GRANT SELECT, INSERT, UPDATE, DELETE ON public.profiles TO service_role;
-- Enable row level security for the table
alter table public.profiles enable row level security;
```
<Admonition type="caution">
Only use primary keys as [foreign key references](https://www.postgresql.org/docs/current/tutorial-fk.html) for schemas and tables like `auth.users` which are managed by Supabase. Postgres lets you specify a foreign key reference for columns backed by a unique index (not necessarily primary keys).
Primary keys are **guaranteed not to change**. Columns, indices, constraints or other database objects managed by Supabase **may change at any time** and you should be careful when referencing them directly.
</Admonition>
To update your `public.profiles` table every time a user signs up, set up a trigger. If the trigger fails, it could block signups, so test your code thoroughly.
```sql
-- inserts a row into public.profiles
create function public.handle_new_user()
returns trigger
language plpgsql
security definer set search_path = ''
as $$
begin
insert into public.profiles (id, first_name, last_name)
values (new.id, new.raw_user_meta_data ->> 'first_name', new.raw_user_meta_data ->> 'last_name');
return new;
end;
$$;
-- trigger the function every time a user is created
create trigger on_auth_user_created
after insert on auth.users
for each row execute procedure public.handle_new_user();
```
## Adding and retrieving user metadata
You can assign metadata to users on sign up:
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="js"
queryGroup="language"
>
<TabPanel id="js" label="JavaScript">
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_KEY!)
// ---cut---
const { data, error } = await supabase.auth.signUp({
email: 'valid.email@supabase.io',
password: 'example-password',
options: {
data: {
first_name: 'John',
age: 27,
},
},
})
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
final res = await supabase.auth.signUp(
email: 'valid.email@supabase.io',
password: 'example-password',
data: {
'first_name': 'John',
'age': 27,
},
);
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
try await supabase.auth.signUp(
email: "valid.email@supabase.io",
password: "example-password",
data: [
"first_name": .string("John"),
"age": .integer(27),
]
)
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
val data = supabase.auth.signUpWith(Email) {
email = "valid.email@supabase.io"
password = "example-password"
data = buildJsonObject {
put("first_name", "John")
put("age", 27)
}
}
```
</TabPanel>
</$Show>
<$Show if="sdk:csharp">
<TabPanel id="csharp" label="C#">
```c#
var session = await supabase.Auth.SignUp("valid.email@supabase.io", "example-password", new SignUpOptions
{
Data = new Dictionary<string, object>
{
{ "first_name", "John" },
{ "age", 27 }
}
});
```
</TabPanel>
</$Show>
</Tabs>
User metadata is stored on the `raw_user_meta_data` column of the `auth.users` table. To view the metadata:
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="js"
queryGroup="language"
>
<TabPanel id="js" label="JavaScript">
```js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_KEY!)
// ---cut---
const {
data: { user },
} = await supabase.auth.getUser()
let metadata = user?.user_metadata
```
</TabPanel>
<$Show if="sdk:dart">
<TabPanel id="dart" label="Dart">
```dart
final User? user = supabase.auth.currentUser;
final Map<String, dynamic>? metadata = user?.userMetadata;
```
</TabPanel>
</$Show>
<$Show if="sdk:swift">
<TabPanel id="swift" label="Swift">
```swift
let user = try await supabase.auth.user()
let metadata = user.userMetadata
```
</TabPanel>
</$Show>
<$Show if="sdk:kotlin">
<TabPanel id="kotlin" label="Kotlin">
```kotlin
val user = supabase.auth.retrieveUserForCurrentSession()
//Or you can use the user from the current session:
val user = supabase.auth.currentUserOrNull()
val metadata = user?.userMetadata
```
</TabPanel>
</$Show>
<$Show if="sdk:csharp">
<TabPanel id="csharp" label="C#">
```c#
var user = supabase.Auth.CurrentUser;
var metadata = user?.UserMetadata;
```
</TabPanel>
</$Show>
</Tabs>
## Deleting users
You may delete users directly or via the management console at Authentication > Users. Note that deleting a user from the `auth.users` table does not automatically sign out a user. As Supabase makes use of JSON Web Tokens (JWT), a user's JWT will remain "valid" until it has expired.
<Admonition type="caution">
You cannot delete a user if they are the owner of any objects in Supabase Storage.
You will encounter an error when you try to delete an Auth user that owns any Storage objects. If this happens, try deleting all the objects for that user, or reassign ownership to another user.
</Admonition>
### Removing account access
When the goal is to remove an account so it can no longer access your app, delete the auth user with [`auth.admin.deleteUser()`](/docs/reference/javascript/auth-admin-deleteuser). With the default `shouldSoftDelete: false`, this removes the row from `auth.users`, which cascades to `auth.sessions` and invalidates the user's refresh tokens — so the account can no longer mint new access tokens.
A few things are _not_ a substitute for deleting the user:
- A temporary [ban](/docs/reference/javascript/auth-admin-updateuserbyid) only blocks sign-in for its duration and does not revoke existing sessions.
- Marking the account as deleted only in your own application tables leaves the `auth.users` row intact, so it can still authenticate and refresh.
Deleting the user still cannot retroactively invalidate an access token that was already issued. Supabase access tokens are stateless JWTs, so a token already in the user's hands stays valid until its `exp` claim passes, and during that window the account can still call the API. You have two ways to handle this window:
- **Bound it:** keep the [access token (JWT) expiry](/docs/guides/auth/sessions) short, so any outstanding token expires soon after you delete the user.
- **Close it for sensitive operations:** validate the `session_id` claim against the `auth.sessions` table on those operations. Because deleting the user removes the session row, an outstanding token fails this check — but only on the requests where you perform it; other API calls still accept the token until `exp`.
See [User sessions](/docs/guides/auth/sessions) for details.
## Exporting users
As Supabase is built on top of Postgres, you can query the `auth.users` and `auth.identities` table via the `SQL Editor` tab to extract all users:
```sql
select * from auth.users;
```
You can then export the results as CSV.