Authentication Model
All ARK products use Supabase Auth and share a single user identity table. This page explains how login works, how invitations work, and how the role system maps onto product permissions.
One identity, every product
When you sign up to your first ARK product, Supabase Auth creates a
user record in auth.users and an ARK product creates a matching
row in profiles. From that moment, the same email/password pair
works in every ARK product you have installed against the same
Supabase project.
auth.users (Supabase-managed)
│
│ id (uuid)
▼
profiles (ARK platform table)
│ email, name, avatar, role
│
│ profile_id
▼
team_members → roles → permissions
Sessions are issued as JWTs and stored in HTTP-only cookies. Each
ARK product reads the cookie on every request and looks up the
user's profiles row to determine identity and role.
Login methods
ARK products support, by default:
- Email + password — primary, works everywhere.
- Magic link — Supabase emails a one-time login link. Useful for users who forget passwords.
- GitHub OAuth — optional. Useful for teams that already use GitHub. Enable it under Supabase → Authentication → Providers → GitHub.
Other Supabase-supported providers (Google, Microsoft, Slack, etc.) work the same way — enable in Supabase, no code changes required in your ARK deployment.
Invite-only by default
ARK products ship with public signup disabled for production deployments. New users join by invitation only.
To invite someone:
- Log in to any ARK product as an admin.
- Open the Team or Members panel.
- Enter the invitee's email and pick a role.
- ARK calls Supabase's
inviteUserByEmailAPI. Supabase emails the invite link. - Invitee clicks the link, picks a password, lands inside your deployment as a member of your team.
To re-enable open signup (e.g., for an internal demo):
- Supabase → Authentication → Providers → Email.
- Set Enable Email Signups to on.
The role system
ARK ships with three roles. You can add more, but most deployments don't need to.
| Role | Default permissions |
|---|---|
admin | Full read/write across all products. Can invite and remove users. Can promote and demote others. |
member | Read/write within the teams they belong to. Cannot manage users or change settings. |
guest | Read-only access to specific resources (e.g., a single Comms channel, a single Ink space). Used for sharing with people outside your team. |
The first user to sign up automatically gets the admin role.
Subsequent users default to member.
How a role becomes a permission
When a request comes in:
- The product reads the user's session and looks up their
profiles.role. - Row Level Security policies on each table consult the role directly (or, more often, indirectly via team membership).
- If the policy passes, the row is returned; otherwise it's silently filtered out.
This means permissions are enforced at the database layer, not in application code. Even if a buyer customizes the UI to remove a permission check, RLS still blocks the underlying query.
For details on RLS, see Security Model.
Cross-product permissions
A user with admin in your Supabase project is admin in every ARK
product on that project. There is no per-product role granularity by
default.
If you need finer-grained access (e.g., "Alice can admin Track but only read Comms"), you have two options:
- Custom role. Add
track_admin,comms_admin, etc. to therolestable and write RLS policies that check for them. This requires customization. - Separate Supabase projects. Run the products in separate projects with separate user lists. This loses cross-product integrations — covered in Shared Database Architecture.
Most deployments don't need this. The default admin / member /
guest model handles 90%+ of teams.
Session management
- Session length: Supabase's default is 1 hour for the access token (auto-refreshed) and 7 days for the refresh token. Configurable under Supabase → Authentication → Sessions.
- Logout: revokes the session immediately on the Supabase side. All ARK products will boot the user to login on next request.
- Multi-device: sessions are independent. Logging out on a phone doesn't log out a desktop session.
Password reset
ARK products use Supabase's built-in password reset flow:
- User clicks Forgot password on the login screen.
- Enters their email.
- Supabase emails a reset link.
- User clicks the link, picks a new password, gets logged in.
The reset link goes to your Site URL (the one you set in Supabase). If the link looks wrong, see the Site URL gotcha.
Two-factor authentication
Supabase supports TOTP-based 2FA. Enable it under Supabase → Authentication → MFA. Once enabled, ARK products show a 2FA prompt after the password step.
We recommend enabling 2FA for all admin users.
OAuth specifics
If you turn on GitHub OAuth (or Google, etc.):
- Supabase → Authentication → Providers → choose provider.
- Follow Supabase's setup guide (you'll need a client ID and secret from the provider).
- Add your Vercel URL to the provider's allowed callback URLs:
https://<your-domain>/auth/v1/callback. - ARK products automatically show a "Sign in with GitHub" (or equivalent) button on the login screen — the buttons appear based on what's enabled in Supabase.
OAuth users still get a profiles row created on first login, so
they're indistinguishable from email/password users at the
application layer.
Programmatic access
If you want a non-human integration to read or write data (e.g., a nightly ETL job), don't use a regular user account. Instead:
- Generate a long-lived API token using the Supabase service role key.
- Set it as a server-side environment variable in your integration.
- Optionally, create a dedicated
servicerole inrolesand write RLS policies that grant it only what it needs.
Never embed the service role key in the ARK product itself or in any frontend code — see Security Model.