Cookies

Better Auth Ruby uses Rack-compatible Set-Cookie headers. The main session cookie is signed or encrypted according to your session configuration.

Set a custom prefix for Better Auth cookies:

auth = BetterAuth.auth(
  secret: ENV.fetch("BETTER_AUTH_SECRET"),
  advanced: {
    cookie_prefix: "my-app"
  }
)

This changes names such as better-auth.session_token to my-app.session_token.

Secure deployments may use the secure cookie prefix automatically when secure cookies are enabled and the cookie attributes allow it.

Custom Cookies

Override individual cookie attributes with advanced.cookies.

auth = BetterAuth.auth(
  secret: ENV.fetch("BETTER_AUTH_SECRET"),
  advanced: {
    cookies: {
      session_token: {
        name: "session",
        attributes: {
          http_only: true,
          secure: true,
          same_site: "lax",
          path: "/"
        }
      }
    }
  }
)

Endpoint and plugin code can also create request-local cookies:

BetterAuth::Endpoint.new(path: "/theme", method: "POST") do |ctx|
  ctx.set_cookie("theme", "dark", same_site: "lax", path: "/")
  ctx.json({status: true})
end

Cross Subdomain Cookies

Enable cross-subdomain cookies when the app and API share a parent domain.

auth = BetterAuth.auth(
  base_url: "https://api.example.com/api/auth",
  trusted_origins: ["https://app.example.com"],
  advanced: {
    cross_subdomain_cookies: {
      enabled: true,
      domain: ".example.com"
    }
  }
)

The cookie domain must be a parent domain shared by both hosts.

Secure Cookies

Use secure cookies in production.

auth = BetterAuth.auth(
  secret: ENV.fetch("BETTER_AUTH_SECRET"),
  advanced: {
    use_secure_cookies: true
  }
)

Secure cookies are sent with Secure, HttpOnly, and the configured SameSite behavior. Local development can keep use_secure_cookies false when serving over plain HTTP.

Safari, ITP, And Cross-Domain Setups

Safari's tracking protections can block third-party cookies when the auth server is on a separate site. Prefer one of these layouts:

  • Put the app and auth server behind the same site, such as app.example.com and api.example.com, then use cross-subdomain cookies.
  • Proxy auth requests through the application origin, such as /api/auth.
  • Use a shared parent domain and HTTPS everywhere.

Using A Reverse Proxy

Proxy /api/auth/* from the frontend origin to the Ruby auth server.

location /api/auth/ {
  proxy_pass http://ruby-auth:3000/api/auth/;
  proxy_set_header Host $host;
  proxy_set_header X-Forwarded-Proto https;
}

If your app trusts proxy headers for base URL inference, configure trusted proxy headers intentionally.

auth = BetterAuth.auth(
  base_url: ->(request) { "https://#{request.host}/api/auth" },
  advanced: {
    trusted_proxy_headers: true
  }
)

Example With Netlify

Configure a Netlify rewrite from the frontend origin to the Ruby auth server:

netlify.toml
[[redirects]]
  from = "/api/auth/*"
  to = "https://api.example.com/api/auth/:splat"
  status = 200
  force = true

Example With Vercel

Configure a Vercel rewrite:

vercel.json
{
  "rewrites": [
    {
      "source": "/api/auth/:path*",
      "destination": "https://api.example.com/api/auth/:path*"
    }
  ]
}

Using A Shared Parent Domain

For app.example.com and api.example.com, configure:

advanced: {
  use_secure_cookies: true,
  cross_subdomain_cookies: {
    enabled: true,
    domain: ".example.com"
  }
}

Keep callback URLs and trusted origins aligned with the public hostnames users actually visit.

On this page