I've setup devise token authentication on my Rails API And it's working properly, however I'm unsure of the most proper secure way to send user credentials when logging in/registering... To give you some context, the API will be used as the backend for a mobile application when it's completed.
Here's what I have for my create method inside of my users_controller.rb:
def create
user = User.new(user_params)
if user.save
render json: user, status: 201
else
render json: { errors: user.errors}, status: 422
end
end
As of now, I'm sending them as parameters through the URL (email, password, password confirmation).
My user_params method:
def user_params
# Seems to expect a user object as the param, unsure of how to replicate this on the app side
# params.require(:user).permit(:email, :password, :password_confirmation)
# Expects to see params[:user] as a string representation of JSON containing fields
# email, password, and password_confirmation.
ActionController::Parameters.new(JSON.parse(params.require(:user))).permit(:email, :password, :password_confirmation)
end
As you can see from my comments, I'm quite unsure how to proceed and I'd like to create as secure a process as possible with the setup that I have.
These are some questions that I have about sending user credentials to my API from a mobile application:
Is it adequate to use HTTPS and send user credentials through parameters?
How can I do this using the first method defined inside of my user_params? It seems that sending a JSON object and parsing it with my second user_param definition (the one not commented out) is the only way to accomplish this. I was originally sending email, password, password_confirmation as their own params, but then I found out that params.require can only take one argument at a time, and then my errors would only show one field that is missing when there could be multiple, hence the reason why I'm sending it as one object.
Am i going about this all wrong? or headed in the right direction?
Thanks for all of your help ahead of time!
Yeah, what you have is a good start.
Is it adequate to use HTTPS and send user credentials through parameters?
It's not only adequate, it's socially responsible of you to send them via HTTPS. At the top of your controller you can force your controller to only respond to ssl requests like so:
force_ssl unless Rails.env.test?
How can I do this using the first method defined inside of my user_params? It seems that sending a JSON object and parsing it with my second user_param definition (the one not commented out) is the only way to accomplish this. I was originally sending email, password, password_confirmation as their own params, but then I found out that params.require can only take one argument at a time, and then my errors would only show one field that is missing when there could be multiple, hence the reason why I'm sending it as one object.
You can reduce this all down to simply:
def user_params
params.permit(:email, :password, :password_confirmation)
end
Rails, by default, will parse JSON into the params hash for you. Using the code above you can also avoid having to put your email and password inside a "user" key on the json object.
{ email: '...', password: '...' } VS. { user: { email: '...', password: '...' } }
Am i going about this all wrong? or headed in the right direction?
You're on the right track. Another minor suggestion, which is totally developer preference is to use keywords for the response types instead of the integers themselves. I just think it reads nicely that way. Here's what it would look like:
def create
user = User.new(user_params)
if user.save
render json: user, status: :created
else
render json: { errors: user.errors }, status: :unprocessable_entity
end
end