Authentication
GoConverso uses Supabase Auth for all authentication. This gives you JWT-based sessions, multiple OAuth providers, and secure row-level access to your data.
Authentication methods
GoConverso supports the following authentication methods:
| Method | Description | Best for |
|---|---|---|
| Email & Password | Traditional sign-up and sign-in | Most users |
| Google OAuth | One-click sign-in with Google | Fast onboarding |
| OTP (One-Time Password) | Email-based magic link or 6-digit code | Client portal access |
| API Key + JWT | Programmatic access | Server-to-server integrations |
API keys
Every GoConverso project has two API keys:
Anon key (public)
The anon key is safe to use in client-side code. It respects Row Level Security policies, meaning users can only access data they are authorized to see.
apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...Service role key (secret)
The service role key bypasses all RLS policies and grants full database access. Use this only in server-side code, edge functions, or secure backend environments.
Never expose the service role key in client-side code. This key has unrestricted access to your entire database, including all user data. Store it in environment variables and use it only in server-side contexts.
JWT tokens
When a user signs in, Supabase issues a JSON Web Token (JWT) that contains the user’s ID, email, and metadata. This token is used to authenticate subsequent API requests.
Token structure
A decoded GoConverso JWT contains:
{
"sub": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"role": "authenticated",
"aud": "authenticated",
"exp": 1706540400,
"iat": 1706536800,
"user_metadata": {
"full_name": "Maria Silva",
"username": "mariasilva",
"niche": "barber"
}
}Token lifecycle
| Event | Behavior |
|---|---|
| Sign in | Access token + refresh token issued |
| Access token expires | Auto-refreshed using refresh token (default: 1 hour) |
| Refresh token expires | User must sign in again (default: 7 days) |
| Sign out | Both tokens invalidated |
Authenticating requests
Every API request must include two headers:
curl -X GET "https://<project-id>.supabase.co/rest/v1/bookings" \
-H "apikey: <your-anon-key>" \
-H "Authorization: Bearer <jwt-access-token>" \
-H "Content-Type: application/json"apikey— identifies your project (use the anon key)Authorization— identifies the authenticated user (use the JWT access token)
Sign up with email and password
Create the user account
const { data, error } = await supabase.auth.signUp({
email: 'newuser@example.com',
password: 'secure-password-123',
options: {
data: {
full_name: 'New User',
username: 'newuser',
niche: 'personal_trainer'
}
}
})Handle the response
On success, the response includes the new user object and a session:
{
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "newuser@example.com",
"user_metadata": {
"full_name": "New User",
"username": "newuser",
"niche": "personal_trainer"
}
},
"session": {
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "v1.MjA5Nj...",
"expires_in": 3600
}
}Profile auto-creation
GoConverso automatically creates a profiles row when a new user signs up. This is handled by a database trigger, so no additional API call is needed.
Sign in with email and password
const { data, error } = await supabase.auth.signInWithPassword({
email: 'user@example.com',
password: 'secure-password-123'
})
if (error) {
console.error('Sign in failed:', error.message)
return
}
// Access token for API requests
const accessToken = data.session.access_tokenOAuth with Google
GoConverso supports Google OAuth for one-click sign-in. This is the recommended method for the fastest user onboarding experience.
Initiate the OAuth flow
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: 'https://converso.pro/auth/callback',
queryParams: {
access_type: 'offline',
prompt: 'consent'
}
}
})Handle the callback
After the user authorizes your app, they are redirected to your callback URL with an authorization code. The Supabase client automatically exchanges this for a session.
// In your callback page (e.g., /auth/callback)
const { data: { session }, error } = await supabase.auth.getSession()
if (session) {
// User is authenticated
console.log('Signed in as:', session.user.email)
}Access Google Calendar (optional)
If you need Google Calendar integration, request additional scopes during the OAuth flow:
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: 'https://converso.pro/auth/callback',
scopes: 'https://www.googleapis.com/auth/calendar.events'
}
})OTP authentication (Client Portal)
GoConverso uses OTP-based authentication for the client portal. Clients receive a 6-digit code via email to access their portal without needing a password.
// Request OTP
const response = await fetch(
'https://<project-id>.supabase.co/functions/v1/send-portal-otp',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'client@example.com',
professionalId: '<professional-uuid>'
})
}
)
// Verify OTP
const verify = await fetch(
'https://<project-id>.supabase.co/functions/v1/verify-portal-otp',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'client@example.com',
code: '123456',
professionalId: '<professional-uuid>'
})
}
)OTP codes expire after 10 minutes and can only be used once. If a client requests a new code, any previously issued codes are automatically invalidated.
Session management
The Supabase client library handles session management automatically, including token refresh. You can listen for auth state changes:
supabase.auth.onAuthStateChange((event, session) => {
switch (event) {
case 'SIGNED_IN':
console.log('User signed in:', session.user.email)
break
case 'SIGNED_OUT':
console.log('User signed out')
break
case 'TOKEN_REFRESHED':
console.log('Token refreshed')
break
}
})Sign out
const { error } = await supabase.auth.signOut()Security best practices
- Store tokens securely — Use
httpOnlycookies or secure storage. Never store JWTs inlocalStoragefor sensitive applications. - Use the anon key on the client — The anon key is scoped by RLS policies. Never use the service role key in browser code.
- Validate tokens server-side — If you build custom endpoints, verify the JWT signature using your project’s JWT secret.
- Enable RLS on all tables — GoConverso has RLS enabled by default. Never disable it without understanding the implications.
- Rotate keys periodically — If you suspect a key has been compromised, rotate it immediately in the Supabase dashboard.
Next, learn how to work with Webhooks to receive real-time event notifications.