Basic Usage

Better Auth Ruby provides the same core server routes as upstream Better Auth:

  • Email and password sign-up/sign-in
  • Social OAuth sign-in and callbacks
  • Session lookup, revocation, and sign-out
  • Password reset and email verification
  • User/account management routes
  • Optional plugins for username, magic link, passkeys, organizations, admin, and more

Create The Auth Object

config/auth.rb
require "better_auth"

auth = BetterAuth.auth(
  secret: ENV.fetch("BETTER_AUTH_SECRET"),
  base_url: ENV.fetch("BETTER_AUTH_URL", "http://localhost:3000"),
  email_and_password: {
    enabled: true
  },
  database: BetterAuth::Adapters::Memory.new
)

Email And Password

Enable email and password auth with email_and_password.

config/auth.rb
auth = BetterAuth.auth(
  secret: ENV.fetch("BETTER_AUTH_SECRET"),
  base_url: ENV.fetch("BETTER_AUTH_URL"),
  email_and_password: {
    enabled: true,
    auto_sign_in: true
  },
  database: BetterAuth::Adapters::Postgres.new(
    url: ENV.fetch("DATABASE_URL")
  )
)

Server-side calls use auth.api. Method names are Ruby snake_case versions of the upstream endpoint keys.

server.rb
result = auth.api.sign_up_email(
  body: {
    email: "ada@example.com",
    password: "password123",
    name: "Ada Lovelace"
  }
)

token = result.fetch(:token)
user = result.fetch(:user)

Sign in:

server.rb
status, headers, body = auth.api.sign_in_email(
  {
    body: {
      email: "ada@example.com",
      password: "password123",
      rememberMe: true
    },
    as_response: true
  }
)

as_response: true returns a Rack-style response tuple so callers can forward Set-Cookie headers.

Sessions

Get the current session from cookies:

server.rb
session = auth.api.get_session(
  headers: {
    "cookie" => request.env["HTTP_COOKIE"]
  }
)

if session
  current_user = session[:user]
end

Sign out:

server.rb
status, headers, body = auth.api.sign_out(
  {
    headers: {
      "cookie" => request.env["HTTP_COOKIE"]
    },
    as_response: true
  }
)

Social Sign-On

Configure providers under social_providers.

config/auth.rb
auth = BetterAuth.auth(
  secret: ENV.fetch("BETTER_AUTH_SECRET"),
  base_url: ENV.fetch("BETTER_AUTH_URL"),
  social_providers: {
    github: BetterAuth::SocialProviders.github(
      client_id: ENV.fetch("GITHUB_CLIENT_ID"),
      client_secret: ENV.fetch("GITHUB_CLIENT_SECRET")
    ),
    google: BetterAuth::SocialProviders.google(
      client_id: ENV.fetch("GOOGLE_CLIENT_ID"),
      client_secret: ENV.fetch("GOOGLE_CLIENT_SECRET")
    )
  }
)

Start a social sign-in:

server.rb
response = auth.api.sign_in_social(
  body: {
    provider: "github",
    callbackURL: "/dashboard",
    errorCallbackURL: "/login",
    newUserCallbackURL: "/welcome",
    disableRedirect: true
  }
)

redirect_url = response.fetch(:url)

Plugins

Plugins are passed as Ruby plugin objects.

config/auth.rb
auth = BetterAuth.auth(
  secret: ENV.fetch("BETTER_AUTH_SECRET"),
  base_url: ENV.fetch("BETTER_AUTH_URL"),
  plugins: [
    BetterAuth::Plugins.username,
    BetterAuth::Plugins.magic_link(
      send_magic_link: ->(email:, url:, token:, **) {
        Mailer.magic_link(email, url).deliver_now
      }
    ),
    BetterAuth::Plugins.two_factor
  ]
)

Plugin route paths match upstream Better Auth. Ruby method names on auth.api are snake_case.

Rack Request Handling

auth is Rack-callable:

config.ru
run auth

When mounted at /api/auth, requests such as POST /api/auth/sign-in/email are handled by the Better Auth router.

On this page