Providers
Supabase
Uses the Ahena CLI (beta). Install it with npm install -g @ahena/cli, or prefix commands with npx @ahena/cli. See Installation. The dashboard covers projects, connections, Doctor, the Stack Graph, plans and approvals without it.
Overview
Ahena connects to a Supabase project you own, checks it, and configures auth URLs. Your
app talks to Supabase directly through the generated src/ahena/ code. Ahena is never
in the request path.
Package: @ahena/provider-supabase · Category: database
Capabilities: postgres, auth, auth-redirects, rls-inspection, migration-inspection, project-health
Connection
Method: API credential (OAuth will be added once Ahena is registered as a Supabase OAuth app).
| Field | Secret | Where it's stored |
|---|---|---|
SUPABASE_ACCESS_TOKEN, a personal access token (sbp_…) |
yes | encrypted_credentials, envelope-encrypted, bound to the environment |
SUPABASE_PROJECT_REF, the 20-letter project id |
no | provider_connections.settings |
SUPABASE_ACCESS_TOKEN=sbp_… ahena connect supabase -e production
# or pipe it, or let Ahena prompt (hidden). Never pass it as an argument.
If you don't pass --set SUPABASE_PROJECT_REF=…, Ahena lists your projects and you pick
one. That listing uses the token without storing it.
Permissions
A Supabase personal access token can manage every project in the account. Ahena
reports this as personal-access-token:full-account and shows a warning when you
connect. Ahena only calls these endpoints (OAuth scope in brackets):
| Endpoint | Used for | Scope |
|---|---|---|
GET /v1/projects, GET /v1/projects/{ref} |
discovery, validation, status | projects:read |
GET /v1/projects/{ref}/health |
service health | projects:read |
GET /v1/projects/{ref}/config/auth |
site URL, redirects, sign-in methods | auth:read |
PATCH /v1/projects/{ref}/config/auth |
site_url and uri_allow_list only, after approval |
auth:write |
GET /v1/projects/{ref}/database/migrations |
migration status | database:read |
POST /v1/projects/{ref}/database/query/read-only |
RLS inspection (pg_class/pg_policy only) |
database:read |
A future OAuth connection needs only those four scopes. The auth-config response also
contains OAuth client secrets, SMTP passwords and SMS tokens. Ahena parses it through
an allowlist (AUTH_FIELDS) and drops everything else at the boundary.
Use a dedicated Supabase account or organization for production if you want to limit what the token can reach.
Capabilities
- Validate: token works, project exists and is active.
- Inspect (
ahena inspect supabase): project, region, Postgres version, site URL, redirect URLs, enabled sign-in methods, migration count. - Doctor (
ahena doctor): see below. - Configure (
ahena configure supabase): site URL and redirect allow list. Setting a missing site URL and adding redirect URLs areCONFIRMATION_REQUIRED; replacing the site URL and removing a redirect URL areDESTRUCTIVE(sign-in links that use the old value stop working). Every change is shown as a diff first. Ahena refuses localhost, plain-HTTP and wildcard-domain URLs in production. - Generate (
ahena generate supabase --framework nextjs|node):src/ahena/providers/supabase.ts,src/ahena/database,src/ahena/auth(each with arawescape hatch) and an.env.example.supabase. The generated code reads keys from environment variables. Sessions never leak between server requests: the browser gets one shared client that keeps the user's session, but on the serversupabase()returns a new client on every call withpersistSession,autoRefreshTokenanddetectSessionInUrloff. supabase-js keeps a signed-in session inside the client instance, so a shared server client would let one user's sign-in apply to other users' requests, and row level security would evaluate as the wrong person. Server code that should act as a user callssupabaseForRequest(accessToken).auth.getUser(accessToken)andauth.signOut(accessToken)take the token explicitly, andauth.signInWithPasswordreturns the session for you to store. For Next.js cookie-based sessions, use@supabase/ssr. It isn't installed or generated for you.
Declare expectations in ahena.config.ts so Doctor and configure know what's intended:
export default {
organization: "acme",
project: "leo",
auth: {
provider: "supabase",
siteUrl: { production: "https://example.com" },
redirectUrls: { production: ["https://example.com/auth/callback"] },
},
};
Doctor also compares supabase/migrations/*.sql in your repository with what's applied.
Limitations
- No OAuth connection yet (personal access token only).
- Ahena doesn't apply migrations or change RLS. It tells you exactly what to run.
- Ahena doesn't fetch the anon or service-role keys. Copy the anon key into your env yourself.
- Ahena never creates or deletes Supabase projects (that would be billable or destructive).
Manual steps
| Situation | What to do |
|---|---|
| Project paused | Restore it in the Supabase dashboard, then ahena doctor. |
| Tables without RLS | Add alter table … enable row level security; plus policies in a migration (Doctor prints the statements). |
| Pending migrations | supabase link --project-ref <ref> then supabase db push. |
| Rotating the token | Create a new token, ahena disconnect supabase, ahena connect supabase, then delete the old token. |
Doctor checks
| Id | Severity | Meaning |
|---|---|---|
supabase.project.status |
PASS / WARNING / FAIL | Project active, transitioning, or paused/failed. |
supabase.health.{db,auth,rest,storage} |
PASS / WARNING / FAIL | Service health from Supabase. |
supabase.db.rls |
PASS / FAIL | Public tables without row level security (readable with the anon key). |
supabase.db.rls_policies |
INFO | RLS enabled but no policies (denies all API access). |
supabase.db.migrations |
INFO / PASS / WARNING / FAIL | Applied vs. repository migrations. Pending is FAIL in production. |
supabase.db.migrations_unknown |
WARNING | Applied migrations missing from the repository. |
supabase.auth.site_url |
PASS / WARNING / FAIL | Missing, development URL in production, or differs from config. |
supabase.auth.redirects_missing |
PASS / FAIL | Redirects declared in ahena.config.ts that Supabase doesn't allow. |
supabase.auth.redirects_local |
WARNING | localhost/private addresses allowed in production. |
supabase.auth.redirects_broad |
FAIL | Wildcards like https://*.com/** that match domains you don't control. |
supabase.auth.autoconfirm |
WARNING | Production sign-ups skip email confirmation. |
supabase.auth.password_length |
WARNING | Minimum password length below 8. |
supabase.auth.providers |
PASS / WARNING | Enabled sign-in methods, or none. |
Disconnect behavior
ahena disconnect supabase removes the connection and deletes the token Ahena stored.
Supabase has no API for revoking a personal access token, so Ahena says so and links
to https://supabase.com/dashboard/account/tokens for you to delete it. Ahena never
deletes projects, data, users or settings in Supabase.