Mỗi Rails app mới đều đến cùng một ngã rẽ: cài Devise trong hai phút, hoặc bỏ cả cuối tuần đọc docs Rodauth và giả vờ mình hiểu mình đang làm gì. Năm nay tôi đã đi cả hai hướng trên các dự án khác nhau, và lựa chọn này không phải về chuyện “cái nào tốt hơn” mà là về bộ đánh đổi nào bạn muốn gánh ở ngày thứ 400. Bài này là cái rubric mà tôi ước mình có vào lần thứ ba mình chọn sai. Nó nghiêng về kiểu Rails app mà một solo founder hay team nhỏ thực sự ship — SaaS, hơi B2B, một hai luồng auth, sau này gắn thêm passkey hay magic link. Nếu bạn đang build một consumer social app với mười hai OAuth provider, bài toán của bạn khác, và tôi sẽ chỉ ra chỗ khác đó.

Chúng ta đang so sánh cái gì

Devise là mặc định. Đây là một gem dựa trên Warden, mount như một Rails engine, với controller và view bạn kế thừa rồi override. Bạn bật các module — database_authenticatable, recoverable, confirmable, lockable, omniauthable — và phần lớn thứ bạn cần cho một SaaS nhỏ chỉ là một hai dòng trong user model.

Rodauth là kẻ nổi lên. Đây là một authentication framework dựa trên Roda, bạn mount vào Rails qua gem rodauth-rails. Nó giả định có một bảng accounts riêng (hoặc migrate bảng users của bạn thành một), giữ password hash ở bảng khác với account, hỗ trợ ràng buộc ở tầng SQL cho những thứ Devise bỏ cho Ruby, và cho bạn một DSL cấu hình đọc như một checklist nghiêm khắc và có quan điểm về mọi quyết định auth bạn phải đưa ra.

Phạm vi của bài này là quyết định green-field: một Rails 8 app, Postgres, Hotwire hoặc React, và một founder muốn auth không trở thành nợ bảo trì sau hai năm.

Bộ tiêu chí tôi dùng

Tôi đã ngừng cố chọn “cái tốt nhất” và bắt đầu chấm điểm trên năm trục. Mỗi trục từ 1–3, và tổng cao hơn thắng cho dự án đó — không phải nói chung.

TrụcĐo cái gìDevise thường đượcRodauth thường được
Time-to-first-loginMất bao lâu để có signup + login + reset chạy đượcCaoTrung bình
Trần customizabilityBạn đẩy được nó tới đâu trước khi phải đánh nhau với frameworkTrung bìnhCao
Mặc định bảo mậtCái bạn có mà không cần đọc source — token rotation, so sánh timing-safe, password pepperTrung bìnhCao
Operational footprintSchema phình ra, migration, ops phải nghĩ tới cái gìThấpTrung bình–cao
Hệ sinh thái & khả năng tuyểnDev kế tiếp có biết nó không? Có câu trả lời StackOverflow từ thập kỷ này không?CaoThấp

Một MVP SaaS “ship trong sáu tuần” điển hình cho founder không kỹ thuật sẽ chấm Devise cao hơn ở dòng 1, dòng 4, và dòng 5 — và ba dòng đó quan trọng hơn dòng 2 và dòng 3 khi app có thể không tồn tại sau sáu tháng.

Một sản phẩm B2B nghiêm túc với audit logging, multi-factor, SAML treo lơ lửng phía trước, và một đợt security review ở năm thứ hai sẽ chấm Rodauth cao hơn ở dòng 2 và 3, và những thứ đó cuối cùng sẽ chiếm phần lớn ngân sách bảo trì.

Hai trục mà bảng đánh giá thấp khoảng cách là mặc định bảo mậttrần customizability. Rodauth ra lò sẵn với reset token được HMAC-sign, lưu password hash tách biệt, và ràng buộc SQL ngay từ đầu. Bạn có thể tái tạo phần lớn những thứ đó trong Devise, nhưng bạn sẽ phải tự viết, và “tôi tự viết code auth” là một câu tôi cố giữ ra khỏi mọi post-mortem.

Mỗi cái cứa bạn ở đâu

Failure mode của Devise là trôi âm thầm. Mặc định ổn vào năm 2014. Một số vẫn ổn; một số đã âm thầm không còn ổn. Confirmation token mặc định không được HMAC — chúng được lưu thành plaintext trong database. Nếu DB của bạn lộ, mấy token đó cũng lộ theo. Bạn sửa được, nhưng phần lớn app tôi xem chưa sửa, vì chẳng ai nói cho họ biết.

Cái bẫy Devise còn lại là override tràn lan. Khoảnh khắc bạn cần một signup flow tùy biến với một bước chen vào giữa, bạn đang subclass Devise::RegistrationsController, override create, gọi super trong block do…end, và cầu nguyện bản major Devise tiếp theo không đổi tên callback. Tôi đã thấy những app mà code auth còn nhiều hơn code business logic.

Failure mode của Rodauth là đau ngay từ đầu. Lần đầu setup bạn sẽ mở ba tab docs cùng một file config 40 dòng và tự hỏi mình đã được gì. Cấu hình explicit — đó là cái chốt — nhưng mỗi tùy chọn bạn bỏ qua là một thứ bạn sẽ hối tiếc. Tách accounts/passwords là đúng về mặt bảo mật và bất ngờ về mặt vận hành.

Cả hai gem chung một cái bẫy thứ ba: chiến lược session. Không gem nào cứu được bạn nếu bạn lưu session 30 ngày trong cookie, không bao giờ rotate khi đổi quyền, và để mọi endpoint bị compromise có thể leo lên admin. Chọn auth library chỉ chiếm một phần nhỏ trong bảo mật session. Chọn gem, rồi đi đọc OWASP về session management. Tôi giữ một checklist riêng cho việc này khi gắn AI feature vào Rails app có sẵn — kỷ luật như nhau.

Nó diễn ra thế nào trên một Rails app thật

Giả sử dự án là một B2B SaaS, MVP bốn-đến-tám tuần, founder không kỹ thuật, hai role (admin và member), email/password cộng Google OAuth, và một câu “để sau thêm SSO khi nào có enterprise customer”.

Với Devise bạn sẽ chạy rails g devise:install, rồi rails g devise User, bật database_authenticatable, recoverable, confirmable, và omniauthable, thêm một strong-parameters override cho form signup, mount omniauth-google-oauth2, viết một Users::OmniauthCallbacksController nho nhỏ, và chương auth của bản build kết thúc trước thứ Tư của tuần đầu. Phần còn lại của dự án bạn dồn cho sản phẩm thực sự. Khi yêu cầu SSO rơi xuống ở năm thứ hai, bạn gắn thêm omniauth-saml per-tenant và có lẽ chửi thề về hệ quả multi-tenancy.

Với Rodauth bạn sẽ mất hai ngày đầu cài cho đúng. Bạn cấu hình bảng accounts, set up HMAC cho token, quyết định dùng feature verify_account hay giả định signup thiện chí, viết một Roda app mount tại /auth, và tích hợp rodauth-oauth cho Google. Đến thứ Sáu tuần đầu bạn có một flow chạy được, đo được là an toàn hơn Devise mặc định. Khi SSO rớt xuống ở năm thứ hai, bạn thêm các mảnh OAuth/SAML có sẵn với cùng DSL và một config diff, không phải đào bới khảo cổ controller.

Cái nào đúng cho dự án đó? Theo kinh nghiệm tôi: Devise. MVP cần ship; founder cần tìm hiểu xem có ai muốn nó không; trần bảo mật bị giới hạn bởi việc sản phẩm chưa tồn tại. Tôi sẽ viết một TODO comment để HMAC confirmation token và đi tiếp. Nếu sản phẩm sống đến năm thứ hai, migration auth sang Rodauth là dự án một tuần, không phải viết lại. (Đọc thêm về đánh đổi này ở Rails SaaS MVP scope.)

Chi phí đổi auth gem sau này là thật nhưng có giới hạn. Chi phí ship trễ sáu tuần vì đầu tư quá tay vào auth ngày đầu là tất cả mọi thứ.

— Ghi chú cho chính tôi

”Xong” trông như thế nào ở mỗi phía

Xong với Devise nghĩa là: reset và confirmation token đã HMAC, session rotation khi đổi password, paranoid mode bật, Devise.email_regexp thắt chặt, lockable cấu hình với chiến lược unlock hợp lý, OmniAuth callback được audit cho race condition lookup provider-và-uid, và một integration test chứng minh user chưa đăng nhập không thể chạm tới route cần auth. Nếu bạn không trả lời “có” cho tất cả, bạn không có Devise chạy ổn, bạn có Devise mặc định.

Xong với Rodauth nghĩa là: mỗi feature bạn bật có spec tương ứng, schema bảng accounts được review theo ràng buộc gem khuyến nghị, secret HMAC của token nằm trong secret manager chứ không nằm trong credentials.yml, email template là của bạn không phải mặc định, và cũng có integration test cho route cần auth y vậy. File config Rodauth nên đọc được như một spec bảo mật — nếu một reviewer không thể nhìn ra chính sách auth của bạn từ config, bạn đang có dây thừng, không phải một cấu hình.

Cả hai vạch đích chia sẻ hai thứ: một threat model viết ra, dù ngắn, và một test suite chứng minh các trường hợp âm. Auth không có negative test là kịch.

Khi nào rubric vỡ

Nếu bạn đang ship một consumer app mà 80% signup là OAuth và password auth chỉ là phương án dự phòng cho trường hợp ngoại lệ, toàn bộ so sánh này nhẹ đi. Tầng OAuth chiếm áp đảo và Devise + omniauth-* là ổn.

Nếu bạn ở ngành chịu quy định — HIPAA, ngân hàng, bất cứ gì có auditor thật — bạn có thể không có quyền chọn. Chọn cái mà team bảo mật của bạn đã review trước đây, vì chi phí review lớn hơn chi phí implement rất nhiều.

Và nếu Rails app của bạn thực ra chỉ là một frontend mỏng cho một auth service riêng — Auth0, WorkOS, Clerk — bạn không cần gem nào cả. Bạn cần một session wrapper và kỷ luật giữ auth service là source of truth.

Một luận điểm tôi sẵn sàng bảo vệ

Đây là luận điểm tôi dám đặt cược: trong số các Rails app chọn Devise hôm nay và sống được ba năm, ít hơn một nửa sẽ đã HMAC confirmation token của họ vào năm thứ ba. Mặc định chính là cái bẫy. Dù bạn chọn library nào, viết ra ba thiết lập bảo mật bạn sẽ verify trong tuần đầu và dán lên trên bàn làm việc. Gem sẽ không cứu bạn. Checklist thì có thể.