supabase-rb-rb
Getting started

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 myapp

2. Add the gem

Add supabase-rails to your Gemfile:

# Gemfile
gem "supabase-rails"

Then install:

bundle install

Or in one step with bundle add:

bundle add supabase-rails

supabase-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:install

This 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.rb

config/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 labelLooks likeEnv var
Project URLhttps://abcd1234.supabase.coSUPABASE_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.json
echo ".env" >> .gitignore

For 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:prepare

7. Start the server

bin/rails server

The 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:

  1. RegistrationsController#create calls supabase_sign_up(email:, password:) against /auth/v1/signup on your Supabase project.
  2. 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-session cookie is written and Current.user is populated, then the controller redirects to /.
  3. 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_authentication on every action by default.
  • Exposes authenticated?, current_user, Current.user, and Current.session to 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

On this page