Belajar Ruby on Rails - Authentication & Authorization
Episode 9 of 27

Belajar Ruby on Rails - Authentication & Authorization

Membedah autentikasi dan otorisasi Rails: has_secure_password untuk password hashing, session & cookies, Rails Authentication generator dan Devise sebagai alternatif, serta Pundit untuk policies dan role-based access control

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah di episode 8 kalian mengelola data dari form, episode 9 membahas dua konsep yang sering tertukar namun sama-sama krusial: authentication (siapa kalian) dan authorization (apa yang boleh kalian lakukan). Auth adalah pintu masuk — tanpa autentikasi yang benar, semua fitur lain bisa diakses orang asing.

Mengapa episode ini penting? Karena autentikasi melibatkan banyak keputusan yang sering salah dipahami: di mana password di-hash, bagaimana session disimpan, dan bagaimana membedakan peran pengguna. Rails 8 memberikan alat modern untuk ini — has_secure_password, session berbasis cookie, dan generator Authentication bawaan — dan episode ini menjelaskan mengapa desainnya seperti itu, bukan sekadar memakai gem.

has_secure_password: Hash Bukan Simpan Mentah

Dasar autentikasi Rails adalah has_secure_password — makro yang menangani hashing password dengan bcrypt:

RubyUser dengan has_secure_password
class User < ApplicationRecord
  has_secure_password
 
  validates :email, presence: true, uniqueness: true
  validates :password, length: { minimum: 8 }, if: -> { password.present? }
end

Yang disediakan has_secure_password:

  • Kolom password_digest di tabel (bukan password).
  • Method password= dan password_confirmation= (opsional, untuk konfirmasi).
  • Method authenticate(password) yang memverifikasi hash — mengembalikan user atau false.
  • Validasi otomatis password minimal 6 karakter (bisa ditimpa).

Kuncinya: database hanya menyimpan password_digest — hasil bcrypt yang irreversible. Sekalipun database bocor, password asli tidak bisa dibaca. Ini standar yang wajib ada di aplikasi apa pun.

Session & Cookies

Setelah login, Rails perlu mengingat siapa user di request berikutnya — lewat session yang disimpan di cookie (tertanda dan terenkripsi):

RubyLogin dan session
def create
  user = User.find_by(email: params[:email])
 
  if user&.authenticate(params[:password])
    session[:user_id] = user.id
    redirect_to root_path, notice: "Login berhasil"
  else
    flash.now[:alert] = "Email atau password salah"
    render :new, status: :unprocessable_entity
  end
end
 
def destroy
  session.delete(:user_id)
  redirect_to login_path, notice: "Logout berhasil"
end

session[:user_id] = user.id menyimpan ID di cookie yang ditandatangani dengan secret key — user tidak bisa mengubahnya tanpa membatalkan tanda tangan. Helper current_user lalu membaca session:

Rubycurrent_user helper
def current_user
  @current_user ||= User.find_by(id: session[:user_id])
end

Note

Cookies dihasilkan dan didekripsi dengan secret key dari config/master.key (Rails Credentials, episode 16). Jika key hilang, semua session user menjadi tidak valid — simpan master.key di tempat aman (vault/secret manager), bukan di repo.

Rails Authentication Generator (Rails 8)

Rails 8 menghadirkan generator autentikasi resmi yang membuat seluruh flow — model, controller, session, dan view:

Rails Authentication generator
bin/rails g authentication
bin/rails db:migrate

Yang dihasilkan generator ini:

  • Model User dengan has_secure_password dan email_verification token.
  • Controllers SessionsController, PasswordsController, RegistrationsController.
  • Route: login, logout, signup, plus reset password.
  • Email verifikasi via ActiveJob + mailer.

Ini adalah pilihan terbaik untuk app baru: default Rails yang aman, tanpa gem tambahan. Devise tetap relevan saat kalian butuh fitur lebih (konfirmasi, lockout, OmniAuth, admin engine).

Authorization: Pundit & Policies

Autentikasi hanya menjawab siapa; otorisasi menjawab boleh apa. Pundit adalah pendekatan populer berbasis policy objects:

Install Pundit
bundle add pundit
bin/rails g pundit:install

Policy adalah class Ruby murni:

RubyPostPolicy
class PostPolicy < ApplicationPolicy
  def index?   = true
  def show?    = true
 
  def create?  = user.present?
  def update?  = record.user == user || user.admin?
  def destroy? = record.user == user || user.admin?
end

Dipanggil dari controller:

Rubyauthorize di controller
def update
  @post = Post.find(params[:id])
  authorize @post
  @post.update!(post_params)
  redirect_to @post
end

authorize @post memanggil PostPolicy#update?; jika false, Pundit melempar Pundit::NotAuthorizedError (menjadi 403). Keuntungan policy object: aturan izin bisa diuji terpisah dan dipakai ulang di view.

Role-Based Access (RBAC)

Kombinasi roles + policies menciptakan RBAC sederhana. Tambahkan kolom role pada User:

Migration tambah role
bin/rails g migration AddRoleToUsers role:integer default:0
RubyEnum role di model
class User < ApplicationRecord
  enum :role, { user: 0, editor: 1, admin: 2 }
end

Sekarang user.admin?, user.editor!, dan user.role tersedia otomatis. Policy mengkombinasikan peran:

RubyPolicy dengan role
class PostPolicy < ApplicationPolicy
  def publish?
    user.admin? || user.editor?
  end
end

Pola umum: halaman admin dibungkus di Admin:: namespace (episode 4) dengan filter require_admin di Admin::BaseController.

Common Pitfalls

  • has_secure_password tanpa bcrypt di Gemfile — Rails sudah menyertakannya, tapi pastikan tidak dihapus; bcrypt wajib.
  • Login tanpa rate limit — endpoint login tanpa throttle adalah target brute-force; solusinya di episode 20.
  • Authn vs authz tertukar — login ≠ izin akses; selalu pasang authorize pada setiap action sensitif.
  • Session di localStorage — jangan simpan session ID di localStorage; cookie Rails sudah aman.
  • user&.authenticate dihilangkan — pattern find_by lalu authenticate terpisah membuat timing attack user enumeration; pakai satu ekspresi dengan &..

Penutup

Episode 9 membekali kalian auth Rails: has_secure_password untuk hashing bcrypt, session berbasis cookie, generator Authentication Rails 8, Pundit dengan policy objects untuk authorization, dan enum role untuk RBAC.

Inti yang harus dibawa pulang:

  • has_secure_password menyimpan password_digest, bukan password mentah.
  • Session via cookie tertanda; session[:user_id] + helper current_user.
  • Rails 8 Authentication generator = auth default tanpa gem tambahan.
  • Pundit memisahkan aturan izin ke policy objects; authorize di controller.
  • Enum role (user/editor/admin) + policy = RBAC yang rapi.

Di episode 10 selanjutnya kita akan membedah testing dengan RSpec/Minitest — unit test model, controller, system test dengan Capybara, fixtures vs factories, dan alur TDD. Sampai jumpa di episode 10!