Getting started with Rails Supabase auth
Install supabase-rails and authenticate your first user in a fresh Rails app in under 15 minutes — supabase-rb on Rails, in :web mode, with cookie-backed sessions and a Current.user populated from the verified Supabase JWT.
This is the quickstart for setting up Rails Supabase auth with supabase-rails in :web mode — encrypted cookie sessions, generator-scaffolded sign-in / sign-up / password-reset / OAuth / OTP, and a Current.user object populated from the verified Supabase JWT. Follow it top-to-bottom and you'll end with a running Rails app and a signed-in user.
Use this guide when you want supabase-rb on Rails (no supabase-js on the front end) handling the entire auth surface for a server-rendered monolith. If you're migrating from the Rails 8 bin/rails generate authentication scaffolding, read the Migrating from Rails 8 auth guide alongside this one.
You need: Ruby ≥ 3.1, Rails ≥ 7.1, and a Supabase project. If you don't have a project yet, create one at supabase.com/dashboard — the free tier is enough.
1. Create a Rails app
Skip this step if you already have one.
rails new myapp
cd myapp2. Add the gem
Add supabase-rails to your Gemfile:
# Gemfile
gem "supabase-rails"Then install:
bundle installOr in one step with bundle add:
bundle add supabase-railssupabase-rails depends on supabase-rb — the same gem the standalone Ruby docs cover — so a single bundle install brings both. The Rails layer adds the Rack middleware, the encrypted-cookie session model, generators, and Devise-shape controllers on top.
3. Run the install generator
bin/rails generate supabase:installThis writes the host-app glue for :web mode — one concern, five 3-line controller subclasses, a Current model, and an initializer that sets mode = :web:
create app/controllers/concerns/authentication.rb
create app/controllers/sessions_controller.rb
create app/controllers/registrations_controller.rb
create app/controllers/passwords_controller.rb
create app/controllers/otp_controller.rb
create app/controllers/oauth_controller.rb
create app/models/current.rb
create config/initializers/supabase.rb
insert config/routes.rb
insert app/controllers/application_controller.rbconfig/routes.rb gets one line: supabase_authentication_routes, which expands to the full sign-in / sign-up / password-reset / OTP / OAuth route table. application_controller.rb gets include Authentication. The generator is idempotent, so it's safe to re-run — see Generators for the per-route breakdown.
4. Get your Supabase URL and keys
In the Supabase dashboard, open your project, then go to Project Settings → API Keys. You need three values:
| Dashboard label | Looks like | Env var |
|---|---|---|
| Project URL | https://abcd1234.supabase.co | SUPABASE_URL |
Publishable key (or anon on legacy projects) | sb_publishable_... (or eyJ...) | SUPABASE_PUBLISHABLE_KEY |
Secret key (or service_role on legacy projects) | sb_secret_... (or eyJ...) | SUPABASE_SECRET_KEY |
The publishable key is safe to expose in browser code; the secret key bypasses Row-Level Security and must stay server-side. On legacy projects the dashboard still labels these anon and service_role — the values work identically in either format.
JWT verification
:web mode verifies tokens against your project's JWKS — you need a fourth env var, SUPABASE_JWKS_URL, pointing at https://<your-ref>.supabase.co/auth/v1/.well-known/jwks.json (or your self-hosted equivalent). For air-gapped setups, set SUPABASE_JWKS to the inline JSON instead. The gem rejects sign-ins with INVALID_CREDENTIALS if neither is configured.
5. Set the environment variables
For local development, the simplest path is a .env file at the repo root plus the dotenv-rails gem:
bundle add dotenv-rails --group "development,test"# .env (add to .gitignore!)
SUPABASE_URL=https://abcd1234.supabase.co
SUPABASE_PUBLISHABLE_KEY=sb_publishable_xxx
SUPABASE_SECRET_KEY=sb_secret_xxx
SUPABASE_JWKS_URL=https://abcd1234.supabase.co/auth/v1/.well-known/jwks.jsonecho ".env" >> .gitignoreFor production, set the same four variables through your hosting provider's secret manager (Heroku config vars, Fly secrets, Kamal env, Rails encrypted credentials, etc.). See Configuration for the full env-var resolution table, including named-key (SUPABASE_PUBLISHABLE_KEYS={"web":"..."}) and SUPABASE_JWKS (inline) overrides.
6. Set up the database
supabase-rails itself doesn't add migrations — Supabase Auth owns the user table. But a fresh Rails app still needs its own database to boot:
bin/rails db:prepare7. Start the server
bin/rails serverThe app boots on http://localhost:3000. On boot, the Railtie auto-inserts Supabase::Rails::Middleware into the stack and the engine installs the supabase_authentication_routes DSL helper — no extra wiring required.
8. Add a landing page
A fresh Rails app has no root route, and the registration controller redirects to root_url on a successful sign-up. Add a minimal landing controller so the post-sign-up redirect resolves and so the layout renders for the sign-in check below:
bin/rails generate controller Home show# config/routes.rb — replace the commented `root` line at the bottom
root "home#show"Then add an authenticated-state marker to app/views/layouts/application.html.erb inside <body>:
<% if authenticated? %>
Signed in as <%= Current.user.email %>
<%= button_to "Sign out", session_path, method: :delete %>
<% else %>
<%= link_to "Sign in", new_session_path %>
<% end %>9. Sign up your first user
Open http://localhost:3000/registration/new and submit the sign-up form. The default flow:
RegistrationsController#createcallssupabase_sign_up(email:, password:)against/auth/v1/signupon your Supabase project.- If your project has Confirm email disabled (Authentication → Sign In / Up → "Confirm email" toggle in the dashboard), the response includes a session and you're signed in immediately — the encrypted
sb-sessioncookie is written andCurrent.useris populated, then the controller redirects to/. - If Confirm email is enabled (the default on new projects), Supabase emails the user a confirmation link instead. Click it, then sign in at
/session/new.
You should land on the home page with "Signed in as you@example.com" and a sign-out button.
What you just got
After running the install generator, every host controller inherits an Authentication concern that:
- Installs
before_action :require_authenticationon every action by default. - Exposes
authenticated?,current_user,Current.user, andCurrent.sessionto controllers and views. - Adds the
allow_unauthenticated_access(only: …)class macro for opting individual actions out.
Current.user is a Supabase::Rails::User value object built from the verified JWT claims — no extra round-trip, no AR record. Opt into a host-app AR User table with bin/rails generate supabase:user_model when you need belongs_to :user reflections to resolve.
Next steps
Authentication
The Authentication concern, supabase_* helpers, override hooks, and Current.user / Current.session.
Configuration
config.supabase.* keys, env-var resolution, CORS, OAuth providers, and the session cookie.
Generators
supabase:install, supabase:user_model, and supabase:views — what each one writes and how to customise it.
Web mode
How the cookie session, refresh coordinator, and PKCE storage fit together.
Supabase Rails (supabase-rails)
supabase-rails is the official Supabase integration for Ruby on Rails — supabase-rb on Rails, packaged as a Railtie with Rails Supabase auth (sign-in, sign-up, OAuth, password reset, OTP), generators, view templates, and an encrypted-cookie session store.
Configuration
Every config.supabase.* Railtie option for supabase-rails, the environment-variable fallbacks, the CORS behaviour, and the logger.