Deviseless, Headerless Authentication in Rails API
Here’s the requirement:
- You are to build a rails API application
- The initial
/loginrequest will have
- After authenticating, the server must return a unique
session_id(or some kind of access_token, depending on your use case) in the response body, not in the response header like how devise does
- All subsequent requests for the remaining API endpoints must include
session_idin the json request body, not in the request header like how devise does
How would you go about doing this?
Sure you can customize devise by overriding its session controller, or opt for devise token auth gem. Checkout the many ways google shows you.
But if you are building just an API app, devise is overkill. It comes with a lot of features, most of which focus on view files, emails etc.
Instead of resorting to a library, you can build a simple, but effective authentication system yourself. Rails provides all things necessary for it out of the box.
In this tutorial, I’m using Rails 5, but the lesson can be applied for older versions too, with some additional gem installs.
Your User model should have a field to store password. Since we’ll use
has_secure_password, we’ll use the
password_digest field for that.
The session_id field for each user will have to be unique for all users. Only based on this we’ll be able to find the logged in user. Each login request should be responded with unique session_id. We can use rails 5’s new
has_secure_token for this.
Once this is done, with a user record present already, we can login like so:
# some controller def login user = User.find_by username: params[:username] if user.authenticate(params[:password]) user.regenerate_session_id @session_id = user.session_id else # inform login failure end end
user.authenticate(password) method is provided by
has_secure_password. You know what it does.
user.regenerate_session_id method is provided by
has_secure_token. Calling it each time updates the
session_id field with new unique token each time. We’d want that because each successful login should generate a new session_id. Old session_ids shouldn’t be possible to use.
The excellent Railscasts video on building authentication from scracth was instrumental in helping me implement this simple and effective solution.
Also, try to simplify things when you can. Devise need not be the de-facto gem for your authentication needs.