Authentication¶
The Supabase Auth module implements IUserContext using GoTrue, Supabase's authentication service. It resolves the current user by calling the GoTrue /user endpoint with the bearer token from the incoming HTTP request.
Effects Module¶
The pre-built AuthModule wraps IUserContext as an effect. Include it in your module:
[EffectsModule(typeof(AuthModule))]
[EffectsModule(typeof(StorageModule))]
public partial class AppModule;
In development, AuthModule registers a StubUserContext that returns a fixed test user. In production, AddSupabaseAuth() replaces it with GoTrue-backed authentication:
// Production — Supabase GoTrue
options.AddSupabaseAuth();
// Alternative — Deepstaging JWT + Google OAuth
services.AddDeepstagingAuth(jwt => ..., google => ...);
Overview¶
This registers:
ISupabaseTokenAccessor→HttpContextTokenAccessor— extracts theAuthorization: Bearer {token}headerIUserContext→SupabaseUserContext— calls GoTrue to resolve the user
How It Works¶
Client Request
│
├─ Authorization: Bearer <supabase-jwt>
│
▼
HttpContextTokenAccessor
│ extracts JWT from header
▼
SupabaseUserContext
│ calls GET /auth/v1/user
▼
GoTrue validates token
│ returns user profile
▼
UserClaims(UserId, Email, Name)
The token is validated server-side by GoTrue on every request. This means:
- Banned or deleted users are immediately rejected
- No local JWT validation or key management needed
- Token refresh is handled by the Supabase client SDK
Usage¶
Inject IUserContext anywhere in your application:
public class OrderHandler(IUserContext userContext)
{
public async Task<Order> Handle(CreateOrderCommand cmd)
{
var user = await userContext.GetCurrentUser();
return new Order(user.UserId, cmd.Items);
}
}
For optional authentication:
var user = await userContext.GetCurrentUserOrNull();
if (user is null)
return Results.Unauthorized();
Token Accessor¶
The default HttpContextTokenAccessor extracts the bearer token from HttpContext.Request.Headers.Authorization. For non-HTTP scenarios (background jobs, WebSocket handlers), implement ISupabaseTokenAccessor:
public sealed class CustomTokenAccessor : ISupabaseTokenAccessor
{
public string? GetAccessToken() => /* your token source */;
}
// Register before AddSupabaseAuth()
services.AddSingleton<ISupabaseTokenAccessor, CustomTokenAccessor>();
GoTrue Client¶
The underlying SupabaseAuthClient is a generated HTTP Client that exposes the full GoTrue API:
| Method | Description |
|---|---|
SignUp(email, password) |
Create a new user |
SignInWithPassword(email, password) |
Email/password sign-in |
SignInWithOtp(email) |
Magic link sign-in |
SignInWithOAuth(provider) |
OAuth redirect URL |
GetUser(authorization) |
Get current user profile |
UpdateUser(authorization, body) |
Update user metadata |
SignOut(authorization) |
Invalidate session |
RefreshToken(refreshToken) |
Refresh access token |
ResetPasswordForEmail(email) |
Send password reset |
InviteUserByEmail(email) |
Admin: invite user |
AdminGetUser(userId) |
Admin: get any user |
AdminDeleteUser(userId) |
Admin: delete user |
AdminListUsers() |
Admin: list all users |
Inject SupabaseAuthClient directly when you need operations beyond IUserContext.
ISupabaseAuth Effects¶
For effects-based access to GoTrue operations, use SupabaseAuthModule. This wraps the full auth API as composable effects:
Register the implementation:
Then compose auth operations inside your effect pipelines:
public static Eff<AppRuntime, Unit> InviteAndNotify(string email) =>
from session in AppEffects.SupabaseAuth.SignUpAsync<AppRuntime>(email, GeneratePassword())
from _ in AppEffects.Notify.SendAsync<AppRuntime>(new UserInvited(email))
select unit;
Available Operations¶
| Effect Method | Description |
|---|---|
SignUpAsync |
Create a new user account |
SignInWithPasswordAsync |
Email/password authentication |
SendOtpToEmailAsync |
Send magic link or OTP via email |
SendOtpToPhoneAsync |
Send OTP via SMS |
VerifyEmailOtpAsync |
Verify email OTP code |
VerifyPhoneOtpAsync |
Verify phone OTP code |
RefreshSessionAsync |
Refresh an access token |
GetCurrentUserAsync |
Get the authenticated user profile |
UpdateUserAsync |
Update user metadata |
SendPasswordRecoveryAsync |
Send password reset email |
SignOutAsync |
Sign out and invalidate session |
EnrollMfaFactorAsync |
Enroll a new MFA factor (TOTP) |
ChallengeMfaFactorAsync |
Create an MFA challenge |
VerifyMfaChallengeAsync |
Verify an MFA challenge code |
UnenrollMfaFactorAsync |
Remove an MFA factor |
Row Level Security¶
Supabase Auth pairs with Row Level Security (RLS) for defense-in-depth. RLS policies run inside Postgres and enforce access rules regardless of which application code queries the data:
-- Users can only see their own orders
CREATE POLICY "Users see own orders" ON orders
FOR SELECT
USING (auth.uid() = user_id);
This complements application-level authorization (Dispatch Authorization) — even if a bug bypasses your application checks, the database rejects unauthorized access.